/products/photocrati_nextgen/modules/nextgen_xmlrpc/package.module.nextgen_xmlrpc.php

  1. <?php 
  2. /** 
  3. * Provides AJAX actions for JSON API interface 
  4. * @mixin C_Ajax_Controller 
  5. * @adapts I_Ajax_Controller 
  6. */ 
  7. class A_NextGen_API_Ajax extends Mixin 
  8. var $nextgen_api = NULL; 
  9. function get_nextgen_api() 
  10. if (is_null($this->nextgen_api)) { 
  11. $this->nextgen_api = C_NextGen_API::get_instance(); 
  12. return $this->nextgen_api; 
  13. function get_nextgen_api_path_list_action() 
  14. $api = $this->get_nextgen_api(); 
  15. $username = $this->object->param('q'); 
  16. $password = $this->object->param('z'); 
  17. $app_config = $this->object->param('app_config'); 
  18. $user_obj = wp_authenticate($username, $password); 
  19. $response = array(); 
  20. if ($user_obj != null && !is_a($user_obj, 'WP_Error')) { 
  21. wp_set_current_user($user_obj->ID); 
  22. $ftp_method = isset($app_config['ftp_method']) ? $app_config['ftp_method'] : 'ftp'; 
  23. $creds = array('connection_type' => $ftp_method == 'sftp' ? 'ssh' : 'ftp', 'hostname' => $app_config['ftp_host'], 'port' => $app_config['ftp_port'], 'username' => $app_config['ftp_user'], 'password' => $app_config['ftp_pass']); 
  24. require_once ABSPATH . 'wp-admin/includes/file.php'; 
  25. $wp_filesystem = $api->create_filesystem_access($creds); 
  26. $root_path = null; 
  27. $base_path = null; 
  28. $plugin_path = null; 
  29. if ($wp_filesystem) { 
  30. $root_path = $wp_filesystem->wp_content_dir(); 
  31. $base_path = $wp_filesystem->abspath(); 
  32. $plugin_path = $wp_filesystem->wp_plugins_dir(); 
  33. } else { 
  34. // fallbacks when unable to connect, try to see if we know the path already 
  35. $root_path = get_option('ngg_ftp_root_path'); 
  36. if (defined('FTP_BASE')) { 
  37. $base_path = FTP_BASE; 
  38. if ($root_path == null && defined('FTP_CONTENT_DIR')) { 
  39. $root_path = FTP_CONTENT_DIR; 
  40. if (defined('FTP_PLUGIN_DIR')) { 
  41. $plugin_path = FTP_PLUGIN_DIR; 
  42. if ($base_path == null && $root_path != null) { 
  43. $base_path = dirname($root_path); 
  44. if ($root_path == null && $base_path != null) { 
  45. $root_path = rtrim($base_path, '/\\') . '/wp-content/'; 
  46. if ($plugin_path == null && $base_path != null) { 
  47. $plugin_path = rtrim($base_path, '/\\') . '/wp-content/plugins/'; 
  48. if ($root_path != NULL) { 
  49. $response['result'] = 'ok'; 
  50. $response['result_object'] = array('root_path' => $root_path, 'wp_content_path' => $root_path, 'wp_base_path' => $base_path, 'wp_plugin_path' => $plugin_path); 
  51. } else { 
  52. if ($wp_filesystem != null) { 
  53. $response['result'] = 'error'; 
  54. $response['error'] = array('code' => C_NextGen_API::ERR_FTP_NO_PATH, 'message' => __('Could not determine FTP path.', 'nggallery')); 
  55. } else { 
  56. $response['result'] = 'error'; 
  57. $response['error'] = array('code' => C_NextGen_API::ERR_FTP_NOT_CONNECTED, 'message' => __('Could not connect to FTP to determine path.', 'nggallery')); 
  58. } else { 
  59. $response['result'] = 'error'; 
  60. $response['error'] = array('code' => C_NextGen_API::ERR_NOT_AUTHENTICATED, 'message' => __('Authentication Failed.', 'nggallery')); 
  61. return $response; 
  62. function enqueue_nextgen_api_task_list_action() 
  63. $api = $this->get_nextgen_api(); 
  64. $username = $this->object->param('q'); 
  65. $password = $this->object->param('z'); 
  66. $response = array(); 
  67. $user_obj = wp_authenticate($username, $password); 
  68. if ($user_obj != null && !is_a($user_obj, 'WP_Error')) { 
  69. wp_set_current_user($user_obj->ID); 
  70. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  71. $app_config = $this->object->param('app_config'); 
  72. $task_list = $this->object->param('task_list'); 
  73. if ($task_list != null) { 
  74. $task_count = count($task_list); 
  75. $auth_count = 0; 
  76. foreach ($task_list as &$task_item) { 
  77. $task_id = isset($task_item['id']) ? $task_item['id'] : null; 
  78. $task_name = isset($task_item['name']) ? $task_item['name'] : null; 
  79. $task_type = isset($task_item['type']) ? $task_item['type'] : null; 
  80. $task_query = isset($task_item['query']) ? $task_item['query'] : null; 
  81. $type_parts = explode('_', $task_name); 
  82. $type_context = array_pop($type_parts); 
  83. $type_action = array_pop($type_parts); 
  84. $task_auth = false; 
  85. switch ($task_type) { 
  86. case 'gallery_add': 
  87. $task_auth = $security->is_allowed('nextgen_edit_gallery'); 
  88. break; 
  89. case 'gallery_remove': 
  90. case 'gallery_edit': 
  91. $query_id = $api->get_query_id($task_query['id']); 
  92. $gallery = null; 
  93. // The old NextGEN XMLRPC API had this logic so replicating it here for safety 
  94. if ($query_id) { 
  95. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  96. $gallery = $gallery_mapper->find($query_id); 
  97. if ($gallery != null) { 
  98. $actor = $security->get_current_actor(); 
  99. $task_auth = $actor->get_entity_id() == $gallery->author || $actor->is_allowed('nextgen_edit_gallery_unowned'); 
  100. } else { 
  101. $task_auth = $security->is_allowed('nextgen_edit_gallery'); 
  102. break; 
  103. case 'album_add': 
  104. $task_auth = $security->is_allowed('nextgen_edit_album'); 
  105. break; 
  106. case 'album_remove': 
  107. $task_auth = $security->is_allowed('nextgen_edit_album'); 
  108. break; 
  109. case 'album_edit': 
  110. $task_auth = $security->is_allowed('nextgen_edit_album'); 
  111. break; 
  112. case 'image_list_move': 
  113. break; 
  114. if ($task_auth) { 
  115. $auth_count++; 
  116. $task_item['auth'] = $task_auth ? 'allow' : 'forbid'; 
  117. if ($task_count == $auth_count) { 
  118. $job_id = $api->add_job(array('user' => $user_obj->ID), $app_config, $task_list); 
  119. if ($job_id != null) { 
  120. $handler_delay = defined('NGG_API_JOB_HANDLER_DELAY') ? intval(NGG_API_JOB_HANDLER_DELAY) : 0; 
  121. $handler_delay = $handler_delay > 0 ? $handler_delay : 30; 
  122. /** in seconds */ 
  123. $response['result'] = 'ok'; 
  124. $response['result_object'] = array('job_id' => $job_id, 'job_handler_url' => home_url('/photocrati_ajax?action=execute_nextgen_api_task_list'), 'job_handler_delay' => $handler_delay); 
  125. } else { 
  126. $response['result'] = 'error'; 
  127. $response['error'] = array('code' => C_NextGen_API::ERR_JOB_NOT_ADDED, 'message' => __('Job could not be added.', 'nggallery')); 
  128. } else { 
  129. $response['result'] = 'error'; 
  130. $response['error'] = array('code' => C_NextGen_API::ERR_NOT_AUTHORIZED, 'message' => __('Authorization Failed.', 'nggallery')); 
  131. } else { 
  132. $response['result'] = 'error'; 
  133. $response['error'] = array('code' => C_NextGen_API::ERR_NO_TASK_LIST, 'message' => __('No task list was specified.', 'nggallery')); 
  134. } else { 
  135. $response['result'] = 'error'; 
  136. $response['error'] = array('code' => C_NextGen_API::ERR_NOT_AUTHENTICATED, 'message' => __('Authentication Failed.', 'nggallery')); 
  137. return $response; 
  138. function execute_nextgen_api_task_list_action() 
  139. $api = $this->get_nextgen_api(); 
  140. $job_list = $api->get_job_list(); 
  141. $response = array(); 
  142. if ($api->is_execution_locked()) { 
  143. $response['result'] = 'ok'; 
  144. $response['info'] = array('code' => C_NextGen_API::INFO_EXECUTION_LOCKED, 'message' => __('Job execution is locked.', 'nggallery')); 
  145. } else { 
  146. if ($job_list != null) { 
  147. $api->set_execution_locked(true); 
  148. $job_count = count($job_list); 
  149. $done_count = 0; 
  150. foreach ($job_list as $job) { 
  151. $result = $api->handle_job($job['id'], $job['data'], $job['app_config'], $job['task_list']); 
  152. if ($result) { 
  153. $done_count++; 
  154. if ($api->should_stop_execution()) { 
  155. break; 
  156. $api->set_execution_locked(false); 
  157. if ($done_count == $job_count) { 
  158. $response['result'] = 'ok'; 
  159. $response['info'] = array('code' => C_NextGen_API::INFO_JOB_LIST_FINISHED, 'message' => __('Job list is finished.', 'nggallery')); 
  160. } else { 
  161. $response['result'] = 'ok'; 
  162. $response['info'] = array('code' => C_NextGen_API::INFO_JOB_LIST_UNFINISHED, 'message' => __('Job list is unfinished.', 'nggallery')); 
  163. } else { 
  164. $response['result'] = 'ok'; 
  165. $response['info'] = array('code' => C_NextGen_API::INFO_NO_JOB_LIST, 'message' => __('Job list is empty.', 'nggallery')); 
  166. return $response; 
  167. /** 
  168. * Class C_NextGen_API 
  169. * @implements I_NextGen_API 
  170. */ 
  171. class C_NextGen_API extends C_Component 
  172. const CRON_KEY = 'nextgen.api.task_list'; 
  173. /** NOTE: these constants' numeric values are used elsewhere, don't change the values */ 
  174. const ERR_NO_TASK_LIST = 1001; 
  175. const ERR_NOT_AUTHENTICATED = 1002; 
  176. const ERR_NOT_AUTHORIZED = 1003; 
  177. const ERR_JOB_NOT_ADDED = 1004; 
  178. const ERR_FTP_NOT_AUTHENTICATED = 1101; 
  179. const ERR_FTP_NOT_CONNECTED = 1102; 
  180. const ERR_FTP_NO_PATH = 1103; 
  181. const INFO_NO_JOB_LIST = 6001; 
  182. const INFO_JOB_LIST_FINISHED = 6002; 
  183. const INFO_JOB_LIST_UNFINISHED = 6003; 
  184. const INFO_EXECUTION_LOCKED = 6004; 
  185. public static $_instances = array(); 
  186. var $_start_time; 
  187. public static function get_instance($context = false) 
  188. if (!isset(self::$_instances[$context])) { 
  189. self::$_instances[$context] = new self($context); 
  190. return self::$_instances[$context]; 
  191. function define($context = false) 
  192. parent::define($context); 
  193. $this->implement('I_NextGen_API'); 
  194. $this->_start_time = time(); 
  195. function should_stop_execution() 
  196. $timeout = defined('NGG_API_JOB_HANDLER_TIMEOUT') ? intval(NGG_API_JOB_HANDLER_TIMEOUT) : intval(ini_get('max_execution_time')) - 3; 
  197. $timeout = $timeout > 0 ? $timeout : 27; 
  198. /** most hosts have a limit of 30 seconds execution time, so 27 should be a safe default */ 
  199. return time() - $this->_start_time >= $timeout; 
  200. function is_execution_locked() 
  201. $lock_time = get_option('ngg_api_execution_lock', 0); 
  202. if ($lock_time == 0) { 
  203. return false; 
  204. $lock_max = defined('NGG_API_EXECUTION_LOCK_MAX') ? intval(NGG_API_EXECUTION_LOCK_MAX) : 0; 
  205. $lock_max = $lock_max > 0 ? $lock_max : 60 * 5; 
  206. /** if the lock is 5 minutes old assume something went wrong and the lock couldn't be unset */ 
  207. $time_diff = time() - $lock_time; 
  208. if ($time_diff > $lock_max) { 
  209. return false; 
  210. return true; 
  211. function set_execution_locked($locked) 
  212. if ($locked) { 
  213. update_option('ngg_api_execution_lock', time()); 
  214. } else { 
  215. update_option('ngg_api_execution_lock', 0); 
  216. function get_job_list() 
  217. return get_option('ngg_api_job_list'); 
  218. function add_job($job_data, $app_config, $task_list) 
  219. $job_list = $this->get_job_list(); 
  220. $job_id = uniqid(); 
  221. while (isset($job_list[$job_id])) { 
  222. $job_id = uniqid(); 
  223. $job = array('id' => $job_id, 'data' => $job_data, 'app_config' => $app_config, 'task_list' => $task_list); 
  224. $job_list[$job_id] = $job; 
  225. update_option('ngg_api_job_list', $job_list); 
  226. return $job_id; 
  227. function _update_job($job_id, $job) 
  228. $job_list = $this->get_job_list(); 
  229. if (isset($job_list[$job_id])) { 
  230. $job_list[$job_id] = $job; 
  231. update_option('ngg_api_job_list', $job_list); 
  232. function remove_job($job_id) 
  233. $job_list = $this->get_job_list(); 
  234. if (isset($job_list[$job_id])) { 
  235. unset($job_list[$job_id]); 
  236. update_option('ngg_api_job_list', $job_list); 
  237. function get_job($job_id) 
  238. $job_list = $this->get_job_list(); 
  239. if (isset($job_list[$job_id])) { 
  240. return $job_list[$job_id]; 
  241. return null; 
  242. function get_job_data($job_id) 
  243. $job = $this->get_job($job_id); 
  244. if ($job != null) { 
  245. return $job['data']; 
  246. return null; 
  247. function get_job_task_list($job_id) 
  248. $job = $this->get_job($job_id); 
  249. if ($job != null) { 
  250. return $job['task_list']; 
  251. return null; 
  252. function set_job_task_list($job_id, $task_list) 
  253. $job = $this->get_job($job_id); 
  254. if ($job != null) { 
  255. $job['task_list'] = $task_list; 
  256. $this->_update_job($job_id, $job); 
  257. return true; 
  258. return false; 
  259. function get_job_status_file($job_id) 
  260. $job = $this->get_job($job_id); 
  261. if ($job != null) { 
  262. return $job['task_list']; 
  263. return null; 
  264. function create_filesystem_access($args, $method = null) 
  265. // taken from wp-admin/includes/file.php but with modifications 
  266. if (!$method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents')) { 
  267. $method = 'ssh2'; 
  268. if (!$method && extension_loaded('ftp')) { 
  269. $method = 'ftpext'; 
  270. if (!$method && (extension_loaded('sockets') || function_exists('fsockopen'))) { 
  271. $method = 'ftpsockets'; 
  272. //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread 
  273. if (!$method) { 
  274. return false; 
  275. require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php'; 
  276. if (!class_exists("WP_Filesystem_{$method}")) { 
  277. /** 
  278. * Filter the path for a specific filesystem method class file. 
  279. * 
  280. * @since 2.6.0 
  281. * 
  282. * @see get_filesystem_method() 
  283. * 
  284. * @param string $path Path to the specific filesystem method class file. 
  285. * @param string $method The filesystem method to use. 
  286. */ 
  287. $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method); 
  288. if (!file_exists($abstraction_file)) { 
  289. return false; 
  290. require_once $abstraction_file; 
  291. $method_class = "WP_Filesystem_{$method}"; 
  292. $wp_filesystem = new $method_class($args); 
  293. //Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default. 
  294. if (!defined('FS_CONNECT_TIMEOUT')) { 
  295. define('FS_CONNECT_TIMEOUT', 30); 
  296. if (!defined('FS_TIMEOUT')) { 
  297. define('FS_TIMEOUT', 30); 
  298. if (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) { 
  299. return false; 
  300. if (!$wp_filesystem->connect()) { 
  301. if ($method == 'ftpext') { 
  302. // attempt connecting with alternative method 
  303. return $this->create_filesystem_access($args, 'ftpsockets'); 
  304. return false; 
  305. //There was an error connecting to the server. 
  306. // Set the permission constants if not already set. 
  307. if (!defined('FS_CHMOD_DIR')) { 
  308. define('FS_CHMOD_DIR', fileperms(ABSPATH) & 0777 | 0755); 
  309. if (!defined('FS_CHMOD_FILE')) { 
  310. define('FS_CHMOD_FILE', fileperms(ABSPATH . 'index.php') & 0777 | 0644); 
  311. return $wp_filesystem; 
  312. // returns an actual scalar ID based on parametric ID (e.g. a parametric ID could represent the query ID from another task) 
  313. function get_query_id($id, &$task_list) 
  314. $task_id = $id; 
  315. if (is_object($task_id) || is_array($task_id)) { 
  316. $id = null; 
  317. // it was specified that the query ID is referencing the result from another task 
  318. if (isset($task_id['target']) && $task_id['target'] == 'task') { 
  319. if (isset($task_id['id']) && isset($task_list[$task_id['id']])) { 
  320. $target_task = $task_list[$task_id['id']]; 
  321. if (isset($target_task['query']['id'])) { 
  322. $id = $target_task['query']['id']; 
  323. return $id; 
  324. // returns an actual scalar ID based on parametric ID (e.g. a parametric ID could represent the resulting object ID from another task) 
  325. function get_object_id($id, &$result_list) 
  326. $task_id = $id; 
  327. if (is_object($task_id) || is_array($task_id)) { 
  328. $id = null; 
  329. // it was specified that the query ID is referencing the result from another task 
  330. if (isset($task_id['target']) && $task_id['target'] == 'task') { 
  331. if (isset($task_id['id']) && isset($result_list[$task_id['id']])) { 
  332. $target_result = $result_list[$task_id['id']]; 
  333. if (isset($target_result['object_id'])) { 
  334. $id = $target_result['object_id']; 
  335. return $id; 
  336. function handle_job($job_id, $job_data, $app_config, $task_list) 
  337. $job_user = $job_data['user']; 
  338. $task_count = count($task_list); 
  339. $done_count = 0; 
  340. $skip_count = 0; 
  341. $task_list_result = array(); 
  342. wp_set_current_user($job_user); 
  343. /** This block does all of the filesystem magic: 
  344. * - determines web paths based on FTP paths 
  345. * - initializes the WP_Filesystem mechanism in case this host doesn't support direct file access 
  346. * (this might not be 100% reliable right now due to NG core not making use of WP_Filesystem) 
  347. */ 
  348. // $ftp_path is assumed to be WP_CONTENT_DIR as accessed through the FTP mount point 
  349. $ftp_path = rtrim($app_config['ftp_path'], '/\\'); 
  350. $full_path = rtrim($app_config['full_path'], '/\\'); 
  351. $root_path = rtrim(WP_CONTENT_DIR, '/\\'); 
  352. $creds = true; 
  353. // WP_Filesystem(true) requests direct filesystem access 
  354. $fs_sep = DIRECTORY_SEPARATOR; 
  355. $wp_fs = null; 
  356. require_once ABSPATH . 'wp-admin/includes/file.php'; 
  357. if (get_filesystem_method() !== 'direct') { 
  358. $fs_sep = '/'; 
  359. $ftp_method = isset($app_config['ftp_method']) ? $app_config['ftp_method'] : 'ftp'; 
  360. $creds = array('connection_type' => $ftp_method == 'sftp' ? 'ssh' : 'ftp', 'hostname' => $app_config['ftp_host'], 'port' => $app_config['ftp_port'], 'username' => $app_config['ftp_user'], 'password' => $app_config['ftp_pass']); 
  361. if (WP_Filesystem($creds)) { 
  362. $wp_fs = $GLOBALS['wp_filesystem']; 
  363. $path_prefix = $full_path; 
  364. if ($wp_fs->method === 'direct') { 
  365. $path_prefix = str_replace($ftp_path, $root_path, $full_path); 
  366. foreach ($task_list as &$task_item) { 
  367. $task_id = isset($task_item['id']) ? $task_item['id'] : null; 
  368. $task_name = isset($task_item['name']) ? $task_item['name'] : null; 
  369. $task_type = isset($task_item['type']) ? $task_item['type'] : null; 
  370. $task_auth = isset($task_item['auth']) ? $task_item['auth'] : null; 
  371. $task_query = isset($task_item['query']) ? $task_item['query'] : null; 
  372. $task_object = isset($task_item['object']) ? $task_item['object'] : null; 
  373. $task_status = isset($task_item['status']) ? $task_item['status'] : null; 
  374. $task_result = isset($task_item['result']) ? $task_item['result'] : null; 
  375. // make sure we don't repeat execution of already finished tasks 
  376. if ($task_status == 'done') { 
  377. $done_count++; 
  378. // for previously finished tasks, store the result as it may be needed by future tasks 
  379. if ($task_id != null && $task_result != null) { 
  380. $task_list_result[$task_id] = $task_result; 
  381. continue; 
  382. // make sure only valid and authorized tasks are executed 
  383. if ($task_status == 'error' || $task_auth != 'allow') { 
  384. $skip_count++; 
  385. continue; 
  386. // the task query ID can be a simple (integer) ID or more complex ID that gets converted to a simple ID, for instance to point to an object that is the result of a previously finished task 
  387. if (isset($task_query['id'])) { 
  388. $task_query['id'] = $this->get_object_id($task_query['id'], $task_list_result); 
  389. $task_error = null; 
  390. switch ($task_type) { 
  391. case 'gallery_add': 
  392. $mapper = C_Gallery_Mapper::get_instance(); 
  393. $gallery = null; 
  394. $gal_errors = ''; 
  395. if (isset($task_query['id'])) { 
  396. $gallery = $mapper->find($task_query['id'], true); 
  397. if ($gallery == null) { 
  398. $title = isset($task_object['title']) ? $task_object['title'] : ''; 
  399. $gallery = $mapper->create(array('title' => $title)); 
  400. if (!$gallery || !$gallery->save()) { 
  401. if ($gallery != null) { 
  402. $gal_errors = $gallery->get_errors(); 
  403. if ($gal_errors != null) { 
  404. $gal_errors = ' [' . json_encode($gal_errors) . ']'; 
  405. $gallery = null; 
  406. if ($gallery != null) { 
  407. $task_status = 'done'; 
  408. $task_result['object_id'] = $gallery->id(); 
  409. } else { 
  410. $task_status = 'error'; 
  411. $task_error = array('level' => 'fatal', 'message' => sprintf(__('Gallery creation failed for "%1$s"%2$s.', 'nggallery'), $title, $gal_errors)); 
  412. break; 
  413. case 'gallery_remove': 
  414. case 'gallery_edit': 
  415. if (isset($task_query['id'])) { 
  416. $mapper = C_Gallery_Mapper::get_instance(); 
  417. $gallery = $mapper->find($task_query['id'], true); 
  418. $error = null; 
  419. if ($gallery != null) { 
  420. if ($task_type == 'gallery_remove') { 
  421. if (!$mapper->destroy($gallery, true)) { 
  422. $error = __('Failed to remove gallery (%1$s).', 'nggallery'); 
  423. } else { 
  424. if ($task_type == 'gallery_edit') { 
  425. if (isset($task_object['name'])) { 
  426. $gallery->name = $task_object['name']; 
  427. if (isset($task_object['title'])) { 
  428. $gallery->title = $task_object['title']; 
  429. if (isset($task_object['description'])) { 
  430. $gallery->galdesc = $task_object['description']; 
  431. if (isset($task_object['preview_image'])) { 
  432. $gallery->previewpic = $task_object['preview_image']; 
  433. if (isset($task_object['property_list'])) { 
  434. $properties = $task_object['property_list']; 
  435. foreach ($properties as $key => $value) { 
  436. $gallery->{$key} = $value; 
  437. // this is used to determine whether the task is complete 
  438. $image_list_unfinished = false; 
  439. if (isset($task_object['image_list']) && $wp_fs != null) { 
  440. $storage_path = isset($task_object['storage_path']) ? $task_object['storage_path'] : null; 
  441. $storage_path = trim($storage_path, '/\\'); 
  442. $storage = C_Gallery_Storage::get_instance(); 
  443. $image_mapper = C_Image_Mapper::get_instance(); 
  444. $creds = true; 
  445. $images_folder = $path_prefix . $fs_sep . $storage_path . $fs_sep; 
  446. $images_folder = str_replace(array('\\', '/'), $fs_sep, $images_folder); 
  447. $images = $task_object['image_list']; 
  448. $result_images = isset($task_result['image_list']) ? $task_result['image_list'] : array(); 
  449. $image_count = count($images); 
  450. $result_image_count = count($result_images); 
  451. for ($image_index = $result_image_count; $image_index < $image_count; $image_index++) { 
  452. $image = $images[$image_index]; 
  453. $image_id = isset($image['id']) ? $image['id'] : null; 
  454. $image_filename = isset($image['filename']) ? $image['filename'] : null; 
  455. $image_path = isset($image['path']) ? $image['path'] : null; 
  456. $image_action = isset($image['action']) ? $image['action'] : null; 
  457. $image_status = 'skip'; 
  458. if ($image_filename == null) { 
  459. $image_filename = basename($image_path); 
  460. $ngg_image = $image_mapper->find($image_id, TRUE); 
  461. // ensure that we don't transpose the image from one gallery to another in case a remoteId is passed in for the image but the gallery associated to the collection cannot be found 
  462. if ($ngg_image && $ngg_image->galleryid != $gallery->id()) { 
  463. $ngg_image = null; 
  464. $image_id = null; 
  465. $image_error = null; 
  466. if ($image_action == "delete") { 
  467. // image was deleted 
  468. if ($ngg_image != null) { 
  469. $settings = C_NextGen_Settings::get_instance(); 
  470. $delete_fine = true; 
  471. if ($settings->deleteImg) { 
  472. if (!$storage->delete_image($ngg_image)) { 
  473. $image_error = __('Could not delete image file(s) from disk (%1$s).', 'nggallery'); 
  474. } else { 
  475. if (!$image_mapper->destroy($ngg_image)) { 
  476. $image_error = __('Could not remove image from gallery (%1$s).', 'nggallery'); 
  477. if ($image_error == null) { 
  478. do_action('ngg_delete_picture', $ngg_image->{$ngg_image->id_field}); 
  479. $image_status = 'done'; 
  480. } else { 
  481. $image_error = __('Could not remove image because image was not found (%1$s).', 'nggallery'); 
  482. } else { 
  483. /** image was added or edited and needs updating */ 
  484. $image_path = $images_folder . $image_path; 
  485. if ($image_path != null && $wp_fs->exists($image_path)) { 
  486. try { 
  487. $ngg_image = $storage->upload_base64_image($gallery, $wp_fs->get_contents($image_path), $image_filename, $image_id, true); 
  488. if ($ngg_image != null) { 
  489. $image_status = 'done'; 
  490. $image_id = $ngg_image->{$ngg_image->id_field}; 
  491. } catch (E_NoSpaceAvailableException $e) { 
  492. $image_error = __('No space available for image (%1$s).', 'nggallery'); 
  493. } catch (E_UploadException $e) { 
  494. $image_error = $e->getMessage . __(' (%1$s).', 'nggallery'); 
  495. } catch (E_No_Image_Library_Exception $e) { 
  496. $error = __('No image library present, image uploads will fail (%1$s).', 'nggallery'); 
  497. // no point in continuing if the image library is not present but we don't break here to ensure that all images are processed (otherwise they'd be processed in further fruitless handle_job calls) 
  498. } catch (E_InsufficientWriteAccessException $e) { 
  499. $image_error = __('Inadequate system permissions to write image (%1$s).', 'nggallery'); 
  500. } catch (E_InvalidEntityException $e) { 
  501. $image_error = __('Requested image with id (%2$s) doesn\'t exist (%1$s).', 'nggallery'); 
  502. } catch (E_EntityNotFoundException $e) { 
  503. // gallery doesn't exist - already checked above so this should never happen 
  504. // delete temporary image 
  505. $wp_fs->delete($image_path); 
  506. } else { 
  507. $image_error = __('Could not find image file for image (%1$s).', 'nggallery'); 
  508. if ($image_error != null) { 
  509. $image_status = 'error'; 
  510. $image['error'] = array('level' => 'fatal', 'message' => sprintf($image_error, $image_filename, $image_id)); 
  511. if ($image_id) { 
  512. $image['id'] = $image_id; 
  513. if ($image_status) { 
  514. $image['status'] = $image_status; 
  515. // append processed image to result image_list array 
  516. $result_images[] = $image; 
  517. if ($this->should_stop_execution()) { 
  518. break; 
  519. $task_result['image_list'] = $result_images; 
  520. $image_list_unfinished = count($result_images) < $image_count; 
  521. // if images have finished processing, remove the folder used to store the temporary images (the folder should be empty due to delete() calls above) 
  522. if (!$image_list_unfinished) { 
  523. $wp_fs->rmdir($images_folder); 
  524. } else { 
  525. if ($wp_fs == null) { 
  526. $error = __('Could not access file system for gallery (%1$s).', 'nggallery'); 
  527. if (!$gallery->save()) { 
  528. if ($error == null) { 
  529. $gal_errors = '[' . json_encode($gallery->get_errors()) . ']'; 
  530. $error = __('Failed to save modified gallery (%1$s). ' . $gal_errors, 'nggallery'); 
  531. } else { 
  532. $error = __('Could not find gallery (%1$s).', 'nggallery'); 
  533. // XXX workaround for $gallery->save() returning false even if successful 
  534. if (isset($task_result['image_list'])) { 
  535. $task_result['object_id'] = $gallery->id(); 
  536. if ($error == null) { 
  537. $task_status = 'done'; 
  538. $task_result['object_id'] = $gallery->id(); 
  539. } else { 
  540. $task_status = 'error'; 
  541. $task_error = array('level' => 'fatal', 'message' => sprintf($error, (string) $task_query['id'])); 
  542. if ($image_list_unfinished) { 
  543. // we override the status of the task when the image list has not finished processing 
  544. $task_status = 'unfinished'; 
  545. } else { 
  546. $task_status = 'error'; 
  547. $task_error = array('level' => 'fatal', 'message' => __('No gallery was specified to edit.', 'nggallery')); 
  548. break; 
  549. case 'album_add': 
  550. $mapper = C_Album_Mapper::get_instance(); 
  551. $name = isset($task_object['name']) ? $task_object['name'] : ''; 
  552. $desc = isset($task_object['description']) ? $task_object['description'] : ''; 
  553. $previewpic = isset($task_object['preview_image']) ? $task_object['preview_image'] : 0; 
  554. $sortorder = isset($task_object['sort_order']) ? $task_object['sort_order'] : ''; 
  555. $page_id = isset($task_object['page_id']) ? $task_object['page_id'] : 0; 
  556. $album = null; 
  557. if (isset($task_query['id'])) { 
  558. $album = $mapper->find($task_query['id'], true); 
  559. if ($album == null) { 
  560. $album = $mapper->create(array('name' => $name, 'previewpic' => $previewpic, 'albumdesc' => $desc, 'sortorder' => $sortorder, 'pageid' => $page_id)); 
  561. if (!$album || !$album->save()) { 
  562. $album = null; 
  563. if ($album != null) { 
  564. $task_status = 'done'; 
  565. $task_result['object_id'] = $album->id(); 
  566. } else { 
  567. $task_status = 'error'; 
  568. $task_error = array('level' => 'fatal', 'message' => __('Album creation failed.', 'nggallery')); 
  569. break; 
  570. case 'album_remove': 
  571. case 'album_edit': 
  572. if (isset($task_query['id'])) { 
  573. $mapper = C_Album_Mapper::get_instance(); 
  574. $album = $mapper->find($task_query['id'], true); 
  575. $error = null; 
  576. if ($album) { 
  577. if ($task_type == 'album_remove') { 
  578. if (!$album->destroy()) { 
  579. $error = __('Failed to remove album (%1$s).', 'nggallery'); 
  580. } else { 
  581. if ($task_type == 'album_edit') { 
  582. if (isset($task_object['name'])) { 
  583. $album->name = $task_object['name']; 
  584. if (isset($task_object['description'])) { 
  585. $album->albumdesc = $task_object['description']; 
  586. if (isset($task_object['preview_image'])) { 
  587. $album->previewpic = $task_object['preview_image']; 
  588. if (isset($task_object['property_list'])) { 
  589. $properties = $task_object['property_list']; 
  590. foreach ($properties as $key => $value) { 
  591. $album->{$key} = $value; 
  592. if (isset($task_object['item_list'])) { 
  593. $item_list = $task_object['item_list']; 
  594. $sortorder = $album->sortorder; 
  595. $count = count($sortorder); 
  596. $album_items = array(); 
  597. for ($index = 0; $index < $count; $index++) { 
  598. $album_items[$sortorder[$index]] = $index; 
  599. foreach ($item_list as $item_info) { 
  600. $item_id = isset($item_info['id']) ? $item_info['id'] : null; 
  601. $item_type = isset($item_info['type']) ? $item_info['type'] : null; 
  602. $item_index = isset($item_info['index']) ? $item_info['index'] : null; 
  603. // translate ID in case this gallery has been created as part of this job 
  604. $item_id = $this->get_object_id($item_id, $task_list_result); 
  605. if ($item_id != null) { 
  606. if ($item_type == 'album') { 
  607. $item_id = 'a' . $item_id; 
  608. $album_items[$item_id] = $count + $item_index; 
  609. asort($album_items); 
  610. $album->sortorder = array_keys($album_items); 
  611. if (!$mapper->save($album)) { 
  612. $error = __('Failed to save modified album (%1$s).', 'nggallery'); 
  613. } else { 
  614. $error = __('Could not find album (%1$s).', 'nggallery'); 
  615. if ($error == null) { 
  616. $task_status = 'done'; 
  617. $task_result['object_id'] = $album->id(); 
  618. } else { 
  619. $task_status = 'error'; 
  620. $task_error = array('level' => 'fatal', 'message' => sprintf($error, (string) $task_query['id'])); 
  621. } else { 
  622. $task_status = 'error'; 
  623. $task_error = array('level' => 'fatal', 'message' => __('No album was specified to edit.', 'nggallery')); 
  624. break; 
  625. case 'gallery_list_get': 
  626. $mapper = C_Gallery_Mapper::get_instance(); 
  627. $gallery_list = $mapper->find_all(); 
  628. $result_list = array(); 
  629. foreach ($gallery_list as $gallery) { 
  630. $gallery_result = array('id' => $gallery->id(), 'name' => $gallery->name, 'title' => $gallery->title, 'description' => $gallery->galdesc, 'preview_image' => $gallery->previewpic); 
  631. $result_list[] = $gallery_result; 
  632. $task_status = 'done'; 
  633. $task_result['gallery_list'] = $result_list; 
  634. break; 
  635. case 'image_list_move': 
  636. break; 
  637. $task_item['result'] = $task_result; 
  638. $task_item['status'] = $task_status; 
  639. $task_item['error'] = $task_error; 
  640. // for previously finished tasks, store the result as it may be needed by future tasks 
  641. if ($task_id != null && $task_result != null) { 
  642. $task_list_result[$task_id] = $task_result; 
  643. // if the task has finished, either successfully or unsuccessfully, increase count for done tasks 
  644. if ($task_status != 'unfinished') { 
  645. $done_count++; 
  646. if ($this->should_stop_execution()) { 
  647. break; 
  648. $this->set_job_task_list($job_id, $task_list); 
  649. if ($task_count > $done_count + $skip_count) { 
  650. // unfinished tasks, return false 
  651. return false; 
  652. } else { 
  653. // everything was finished, remove job and write status file 
  654. $this->remove_job($job_id); 
  655. $status_file = '_ngg_job_status_' . strval($job_id) . '.txt'; 
  656. $status_content = json_encode($task_list); 
  657. if ($wp_fs != null) { 
  658. $status_path = $path_prefix . $fs_sep . $status_file; 
  659. $status_path = str_replace(array('\\', '/'), $fs_sep, $status_path); 
  660. $wp_fs->put_contents($status_path, $status_content); 
  661. } else { 
  662. // if WP_Filesystem failed try one last desperate attempt at direct file writing 
  663. $status_path = str_replace($ftp_path, $root_path, $full_path) . DIRECTORY_SEPARATOR . $status_file; 
  664. $status_path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $status_path); 
  665. file_put_contents($status_path, $status_content); 
  666. return true; 
  667. /** 
  668. * Class C_NextGen_API_XMLRPC 
  669. * @implements I_NextGen_API_XMLRPC 
  670. */ 
  671. class C_NextGen_API_XMLRPC extends C_Component 
  672. public static $_instances = array(); 
  673. function define($context = false) 
  674. parent::define($context); 
  675. $this->implement('I_NextGen_API_XMLRPC'); 
  676. public static function get_instance($context = false) 
  677. if (!isset(self::$_instances[$context])) { 
  678. self::$_instances[$context] = new self($context); 
  679. return self::$_instances[$context]; 
  680. /** 
  681. * Gets the version of NextGEN Gallery installed 
  682. * @return string 
  683. */ 
  684. function get_version() 
  685. return array('version' => NGG_PLUGIN_VERSION); 
  686. /** 
  687. * Login a user 
  688. * @param $username 
  689. * @param $password 
  690. * @return bool|WP_Error|WP_User 
  691. */ 
  692. function _login($username, $password, $blog_id = 1) 
  693. $retval = FALSE; 
  694. if (!is_a($user_obj = wp_authenticate($username, $password), 'WP_Error')) { 
  695. wp_set_current_user($user_obj->ID); 
  696. $retval = $user_obj; 
  697. if (is_multisite()) { 
  698. switch_to_blog($blog_id); 
  699. return $retval; 
  700. function _can_manage_gallery($gallery_id_or_obj, $check_upload_capability = FALSE) 
  701. $retval = FALSE; 
  702. // Get the gallery object, if we don't have it already 
  703. $gallery = NULL; 
  704. if (is_int($gallery_id_or_obj)) { 
  705. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  706. $gallery = $gallery_mapper->find($gallery_id_or_obj); 
  707. } else { 
  708. $gallery = $gallery_id_or_obj; 
  709. if ($gallery) { 
  710. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  711. $actor = $security->get_current_actor(); 
  712. if ($actor->get_entity_id() == $gallery->author) { 
  713. $retval = TRUE; 
  714. } elseif ($actor->is_allowed('nextgen_edit_gallery_unowned')) { 
  715. $retval = TRUE; 
  716. // Optionally, check if the user can upload to this gallery 
  717. if ($retval && $check_upload_capability) { 
  718. $retval = $actor->is_allowed('nextgen_upload_image'); 
  719. return $retval; 
  720. function _add_gallery_properties($gallery) 
  721. if (is_object($gallery)) { 
  722. $image_mapper = C_Image_Mapper::get_instance(); 
  723. $storage = C_Gallery_Storage::get_instance(); 
  724. // Vladimir's Lightroom plugins requires the 'id' to be a string 
  725. // Ask if he can accept integers as well. Currently, integers break 
  726. // his plugin 
  727. $gallery->gid = (string) $gallery->gid; 
  728. // Set other gallery properties 
  729. $image_counter = array_pop($image_mapper->select('DISTINCT COUNT(*) as counter')->where(array("galleryid = %d", $gallery->gid))->run_query(FALSE, FALSE, TRUE)); 
  730. $gallery->counter = $image_counter->counter; 
  731. $gallery->abspath = $storage->get_gallery_abspath($gallery); 
  732. } else { 
  733. return FALSE; 
  734. return TRUE; 
  735. /** 
  736. * Returns a single image object 
  737. * @param $args (blog_id, username, password, pid) 
  738. */ 
  739. function get_image($args, $return_model = FALSE) 
  740. $retval = new IXR_Error(403, 'Invalid username or password'); 
  741. $blog_id = intval($args[0]); 
  742. $username = strval($args[1]); 
  743. $password = strval($args[2]); 
  744. $image_id = intval($args[3]); 
  745. // Authenticate the user 
  746. if ($this->_login($username, $password, $blog_id)) { 
  747. // Try to find the image 
  748. $image_mapper = C_Image_Mapper::get_instance(); 
  749. if ($image = $image_mapper->find($image_id, TRUE)) { 
  750. // Try to find the gallery that the image belongs to 
  751. $gallery_mapper = C_Gallery_Mapper::get_instance(); 
  752. if ($gallery = $gallery_mapper->find($image->galleryid)) { 
  753. // Does the user have sufficient capabilities? 
  754. if ($this->_can_manage_gallery($gallery)) { 
  755. $storage = C_Gallery_Storage::get_instance(); 
  756. $image->imageURL = $storage->get_image_url($image, 'full', TRUE); 
  757. $image->thumbURL = $storage->get_thumb_url($image, TRUE); 
  758. $image->imagePath = $storage->get_image_abspath($image); 
  759. $image->thumbPath = $storage->get_thumb_abspath($image); 
  760. $retval = $return_model ? $image : $image->get_entity(); 
  761. } else { 
  762. $retval = new IXR_Error(403, "You don't have permission to manage gallery #{$image->galleryid}"); 
  763. } else { 
  764. // No gallery found 
  765. $retval = new IXR_Error(404, "Gallery not found (with id #{$image->gallerid})"); 
  766. } else { 
  767. // No image found 
  768. $retval = new IXR_Error(404, "Image not found (with id #{$image_id})"); 
  769. return $retval; 
  770. /** 
  771. * Returns a collection of images 
  772. * @param $args (blog_id, username, password, gallery_id 
  773. */ 
  774. function get_images($args) 
  775. $retval = new IXR_Error(403, 'Invalid username or password'); 
  776. $blog_id = intval($args[0]); 
  777. $username = strval($args[1]); 
  778. $password = strval($args[2]); 
  779. $gallery_id = intval($args[3]); 
  780. // Authenticate the user 
  781. if ($this->_login($username, $password, $blog_id)) { 
  782. // Try to find the gallery 
  783. $mapper = C_Gallery_Mapper::get_instance(); 
  784. if ($gallery = $mapper->find($gallery_id, TRUE)) { 
  785. // Does the user have sufficient capabilities? 
  786. if ($this->_can_manage_gallery($gallery)) { 
  787. $retval = $gallery->get_images(); 
  788. } else { 
  789. $retval = new IXR_Error(403, "You don't have permission to manage gallery #{$image->galleryid}"); 
  790. } else { 
  791. $retval = new IXR_Error(404, "Gallery not found (with id #{$image->gallerid}"); 
  792. return $retval; 
  793. /** 
  794. * Uploads an image to a particular gallery 
  795. * @param $args (blog_id, username, password, data) 
  796. * 
  797. * Data is an assoc array: 
  798. * o string name 
  799. * o string type (optional) 
  800. * o base64 bits 
  801. * o bool overwrite (optional) 
  802. * o int gallery 
  803. * o int image_id (optional) 
  804. * @return image 
  805. */ 
  806. function upload_image($args) 
  807. $retval = new IXR_Error(403, 'Invalid username or password'); 
  808. $blog_id = intval($args[0]); 
  809. $username = strval($args[1]); 
  810. $password = strval($args[2]); 
  811. $data = $args[3]; 
  812. $gallery_id = isset($data['gallery_id']) ? $data['gallery_id'] : $data['gallery']; 
  813. if (!isset($data['override'])) { 
  814. $data['override'] = FALSE; 
  815. if (!isset($data['overwrite'])) { 
  816. $data['overwrite'] = FALSE; 
  817. $data['override'] = $data['overwrite']; 
  818. // Authenticate the user 
  819. if ($this->_login($username, $password, $blog_id)) { 
  820. // Try to find the gallery 
  821. $mapper = C_Gallery_Mapper::get_instance(); 
  822. if ($gallery = $mapper->find($gallery_id, TRUE)) { 
  823. // Does the user have sufficient capabilities? 
  824. if ($this->_can_manage_gallery($gallery, TRUE)) { 
  825. // Upload the image 
  826. $storage = C_Gallery_Storage::get_instance(); 
  827. $image = $storage->upload_base64_image($gallery, $data['bits'], $data['name'], $data['image_id'], $data['override']); 
  828. if ($image) { 
  829. $storage = C_Gallery_Storage::get_instance(); 
  830. $image->imageURL = $storage->get_image_url($image); 
  831. $image->thumbURL = $storage->get_thumb_url($image); 
  832. $image->imagePath = $storage->get_image_abspath($image); 
  833. $image->thumbPath = $storage->get_thumb_abspath($image); 
  834. $retval = $image->get_entity(); 
  835. } else { 
  836. $retval = new IXR_Error(500, "Could not upload image"); 
  837. } else { 
  838. $retval = new IXR_Error(403, "You don't have permission to upload to gallery #{$image->galleryid}"); 
  839. } else { 
  840. $retval = new IXR_Error(404, "Gallery not found (with id #{$image->gallerid}"); 
  841. return $retval; 
  842. /** 
  843. * Edits an image object 
  844. * @param $args (blog_id, username, password, image_id, alttext, description, exclude, other_properties 
  845. */ 
  846. function edit_image($args) 
  847. $alttext = strval($args[4]); 
  848. $description = strval($args[5]); 
  849. $exclude = intval($args[6]); 
  850. $properties = isset($args[7]) ? (array) $args[7] : array(); 
  851. $retval = $this->get_image($args, TRUE); 
  852. if (!$retval instanceof IXR_Error) { 
  853. $retval->alttext = $alttext; 
  854. $retval->description = $description; 
  855. $retval->exclude = $exclude; 
  856. // Other properties can be specified using an associative array 
  857. foreach ($properties as $key => $value) { 
  858. $retval->{$key} = $value; 
  859. // Unset any dynamic properties not part of the schema 
  860. foreach (array('imageURL', 'thumbURL', 'imagePath', 'thumbPath') as $key) { 
  861. unset($retval->{$key}); 
  862. $retval = $retval->save(); 
  863. return $retval; 
  864. /** 
  865. * Deletes an existing image from a gallery 
  866. * @param $args (blog_id, username, password, image_id) 
  867. */ 
  868. function delete_image($args) 
  869. $retval = $this->get_image($args, TRUE); 
  870. if (!$retval instanceof IXR_Error) { 
  871. $retval = $retval->destroy(); 
  872. return $retval; 
  873. /** 
  874. * Creates a new gallery 
  875. * @param $args (blog_id, username, password, title) 
  876. */ 
  877. function create_gallery($args) 
  878. $retval = new IXR_Error(403, 'Invalid username or password'); 
  879. $blog_id = intval($args[0]); 
  880. $username = strval($args[1]); 
  881. $password = strval($args[2]); 
  882. $title = strval($args[3]); 
  883. // Authenticate the user 
  884. if ($this->_login($username, $password, $blog_id)) { 
  885. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  886. if ($security->is_allowed('nextgen_edit_gallery')) { 
  887. $mapper = C_Gallery_Mapper::get_instance(); 
  888. if (($gallery = $mapper->create(array('title' => $title))) && $gallery->save()) { 
  889. $retval = $gallery->id(); 
  890. } else { 
  891. $retval = new IXR_Error(500, "Unable to create gallery"); 
  892. } else { 
  893. $retval = new IXR_Error(403, "Sorry, but you must be able to manage galleries. Check your roles/capabilities."); 
  894. return $retval; 
  895. /** 
  896. * Edits an existing gallery 
  897. * @param $args (blog_id, username, password, gallery_id, name, title, description, preview_pic_id) 
  898. */ 
  899. function edit_gallery($args) 
  900. $retval = new IXR_Error(403, 'Invalid username or password'); 
  901. $blog_id = intval($args[0]); 
  902. $username = strval($args[1]); 
  903. $password = strval($args[2]); 
  904. $gallery_id = intval($args[3]); 
  905. $name = strval($args[4]); 
  906. $title = strval($args[5]); 
  907. $galdesc = strval($args[6]); 
  908. $image_id = intval($args[7]); 
  909. $properties = isset($args[8]) ? (array) $args[8] : array(); 
  910. // Authenticate the user 
  911. if ($this->_login($username, $password, $blog_id)) { 
  912. $mapper = C_Gallery_Mapper::get_instance(); 
  913. if ($gallery = $mapper->find($gallery_id, TRUE)) { 
  914. if ($this->_can_manage_gallery($gallery)) { 
  915. $gallery->name = $name; 
  916. $gallery->title = $title; 
  917. $gallery->galdesc = $galdesc; 
  918. $gallery->previewpic = $image_id; 
  919. foreach ($properties as $key => $value) { 
  920. $gallery->{$key} = $value; 
  921. // Unset dynamic properties not part of the schema 
  922. unset($gallery->counter); 
  923. unset($gallery->abspath); 
  924. $retval = $gallery->save(); 
  925. } else { 
  926. $retval = new IXR_Error(403, "You don't have permission to modify this gallery"); 
  927. } else { 
  928. $retval = new IXR_Error(404, "Gallery #{$gallery_id} doesn't exist"); 
  929. return $retval; 
  930. /** 
  931. * Returns all galleries 
  932. * @param $args (blog_id, username, password) 
  933. */ 
  934. function get_galleries($args) 
  935. $retval = new IXR_Error(403, 'Invalid username or password'); 
  936. $blog_id = intval($args[0]); 
  937. $username = strval($args[1]); 
  938. $password = strval($args[2]); 
  939. // Authenticate the user 
  940. if ($this->_login($username, $password, $blog_id)) { 
  941. // Do we have permission? 
  942. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  943. if ($security->is_allowed('nextgen_edit_gallery')) { 
  944. $mapper = C_Gallery_Mapper::get_instance(); 
  945. $retval = array(); 
  946. foreach ($mapper->find_all() as $gallery) { 
  947. $this->_add_gallery_properties($gallery); 
  948. $retval[$gallery->{$gallery->id_field}] = (array) $gallery; 
  949. } else { 
  950. $retval = new IXR_Error(401, __('Sorry, you must be able to manage galleries')); 
  951. return $retval; 
  952. /** 
  953. * Gets a single gallery instance 
  954. * @param $args (blog_id, username, password, gallery_id) 
  955. */ 
  956. function get_gallery($args, $return_model = FALSE) 
  957. $retval = new IXR_Error(403, 'Invalid username or password'); 
  958. $blog_id = intval($args[0]); 
  959. $username = strval($args[1]); 
  960. $password = strval($args[2]); 
  961. $gallery_id = intval($args[3]); 
  962. // Authenticate the user 
  963. if ($this->_login($username, $password, $blog_id)) { 
  964. $mapper = C_Gallery_Mapper::get_instance(); 
  965. if ($gallery = $mapper->find($gallery_id, TRUE)) { 
  966. if ($this->_can_manage_gallery($gallery)) { 
  967. $this->_add_gallery_properties($gallery); 
  968. $retval = $return_model ? $gallery : $gallery->get_entity(); 
  969. } else { 
  970. $retval = new IXR_Error(403, "Sorry, but you don't have permission to manage gallery #{$gallery->gid}"); 
  971. } else { 
  972. $retval = FALSE; 
  973. return $retval; 
  974. /** 
  975. * Deletes a gallery 
  976. * @param $args (blog_id, username, password, gallery_id) 
  977. */ 
  978. function delete_gallery($args) 
  979. $retval = $this->get_gallery($args, TRUE); 
  980. if (!$retval instanceof IXR_Error and is_object($retval)) { 
  981. $retval = $retval->destroy(); 
  982. return $retval; 
  983. /** 
  984. * Creates a new album 
  985. * @param $args (blog_id, username, password, title, previewpic, description, galleries 
  986. */ 
  987. function create_album($args) 
  988. $retval = new IXR_Error(403, 'Invalid username or password'); 
  989. $blog_id = intval($args[0]); 
  990. $username = strval($args[1]); 
  991. $password = strval($args[2]); 
  992. $title = strval($args[3]); 
  993. $previewpic = isset($args[4]) ? intval($args[4]) : 0; 
  994. $desc = isset($args[5]) ? strval($args[5]) : ''; 
  995. $sortorder = isset($args[6]) ? $args[6] : ''; 
  996. $page_id = isset($args[7]) ? intval($args[7]) : 0; 
  997. // Authenticate the user 
  998. if ($this->_login($username, $password, $blog_id)) { 
  999. // Is request allowed? 
  1000. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  1001. if ($security->is_allowed('nextgen_edit_album')) { 
  1002. $mapper = C_Album_Mapper::get_instance(); 
  1003. $album = $mapper->create(array('name' => $title, 'previewpic' => $previewpic, 'albumdesc' => $desc, 'sortorder' => $sortorder, 'pageid' => $page_id)); 
  1004. if ($album->save()) { 
  1005. $retval = $album->id(); 
  1006. } else { 
  1007. $retval = new IXR_Error(500, "Unable to create album"); 
  1008. return $retval; 
  1009. /** 
  1010. * Returns all albums 
  1011. * @param $args (blog_id, username, password) 
  1012. * @return IXR_Error 
  1013. */ 
  1014. function get_albums($args) 
  1015. $retval = new IXR_Error(403, 'Invalid username or password'); 
  1016. $blog_id = intval($args[0]); 
  1017. $username = strval($args[1]); 
  1018. $password = strval($args[2]); 
  1019. // Authenticate the user 
  1020. if ($this->_login($username, $password, $blog_id)) { 
  1021. // Are we allowed? 
  1022. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  1023. if ($security->is_allowed('nextgen_edit_album')) { 
  1024. // Fetch all albums 
  1025. $mapper = C_Album_Mapper::get_instance(); 
  1026. $retval = array(); 
  1027. foreach ($mapper->find_all() as $album) { 
  1028. // Vladimir's Lightroom plugins requires the 'id' to be a string 
  1029. // Ask if he can accept integers as well. Currently, integers break 
  1030. // his plugin 
  1031. $album->id = (string) $album->id; 
  1032. $album->galleries = $album->sortorder; 
  1033. $retval[$album->{$album->id_field}] = (array) $album; 
  1034. } else { 
  1035. $retval = new IXR_Error(403, "Sorry, you must be able to manage albums"); 
  1036. return $retval; 
  1037. /** 
  1038. * Gets a single album 
  1039. * @param $args (blog_id, username, password, album_id) 
  1040. */ 
  1041. function get_album($args, $return_model = FALSE) 
  1042. $retval = new IXR_Error(403, 'Invalid username or password'); 
  1043. $blog_id = intval($args[0]); 
  1044. $username = strval($args[1]); 
  1045. $password = strval($args[2]); 
  1046. $album_id = intval($args[3]); 
  1047. // Authenticate the user 
  1048. if ($this->_login($username, $password, $blog_id)) { 
  1049. // Are we allowed? 
  1050. $security = $this->get_registry()->get_utility('I_Security_Manager'); 
  1051. if ($security->is_allowed('nextgen_edit_album')) { 
  1052. $mapper = C_Album_Mapper::get_instance(); 
  1053. if ($album = $mapper->find($album_id, TRUE)) { 
  1054. // Vladimir's Lightroom plugins requires the 'id' to be a string 
  1055. // Ask if he can accept integers as well. Currently, integers break 
  1056. // his plugin 
  1057. $album->id = (string) $album->id; 
  1058. $album->galleries = $album->sortorder; 
  1059. $retval = $return_model ? $album : $album->get_entity(); 
  1060. } else { 
  1061. $retval = FALSE; 
  1062. } else { 
  1063. $retval = new IXR_Error(403, "Sorry, you must be able to manage albums"); 
  1064. return $retval; 
  1065. /** 
  1066. * Deletes an existing album 
  1067. * @param $args (blog_id, username, password, album_id) 
  1068. */ 
  1069. function delete_album($args) 
  1070. $retval = $this->get_album($args, TRUE); 
  1071. if (!$retval instanceof IXR_Error) { 
  1072. $retval = $retval->destroy(); 
  1073. return $retval; 
  1074. /** 
  1075. * Edit an existing album 
  1076. * @param $args (blog_id, username, password, album_id, name, preview pic id, description, galleries) 
  1077. */ 
  1078. function edit_album($args) 
  1079. $retval = $this->get_album($args, TRUE); 
  1080. if (!$retval instanceof IXR_Error) { 
  1081. $retval->name = strval($args[4]); 
  1082. $retval->previewpic = intval($args[5]); 
  1083. $retval->albumdesc = strval($args[6]); 
  1084. $retval->sortorder = $args[7]; 
  1085. $properties = isset($args[8]) ? $args[8] : array(); 
  1086. foreach ($properties as $key => $value) { 
  1087. $retval->{$key} = $value; 
  1088. unset($retval->galleries); 
  1089. $retval = $retval->save(); 
  1090. return $retval; 
  1091. /** 
  1092. * Sets the post thumbnail for a post to a NextGEN Gallery image 
  1093. * @param $args (blog_id, username, password, post_id, image_id) 
  1094. * 
  1095. * @return IXR_Error|int attachment id 
  1096. */ 
  1097. function set_post_thumbnail($args) 
  1098. $retval = new IXR_Error(403, 'Invalid username or password'); 
  1099. $blog_id = intval($args[0]); 
  1100. $username = strval($args[1]); 
  1101. $password = strval($args[2]); 
  1102. $post_ID = intval($args[3]); 
  1103. $image_id = intval($args[4]); 
  1104. // Authenticate the user 
  1105. if ($this->_login($username, $password, $blog_id)) { 
  1106. if (current_user_can('edit_post', $post_ID)) { 
  1107. $retval = C_Gallery_Storage::get_instance()->set_post_thumbnail($post_ID, $image_id); 
  1108. } else { 
  1109. $retval = new IXR_Error(403, "Sorry but you need permission to do this"); 
  1110. return $retval; 
.