diff --git a/auth/services_keyauth/services_keyauth.admin.inc b/auth/services_keyauth/services_keyauth.admin.inc index 1ebf892..c7ffa40 100644 --- a/auth/services_keyauth/services_keyauth.admin.inc +++ b/auth/services_keyauth/services_keyauth.admin.inc @@ -1,5 +1,5 @@ t('External domain allowed to use this key.'), '#required' => TRUE, ); - + $methods = services_get_all(); foreach ($methods as $method) { - $form_methods[$method['#method']] = $method['#method']; + $form_methods[$method['method']] = $method['method']; } $form['method_access'] = array( @@ -128,7 +128,7 @@ function services_keyauth_admin_keys_save(&$key) { db_query("INSERT INTO {services_key_permissions} (kid, method) VALUES ('%s', '%s')", $key['kid'], $value); } } - return $return; + return $return; } function services_keyauth_admin_keys_delete($kid) { diff --git a/auth/services_keyauth/services_keyauth.inc b/auth/services_keyauth/services_keyauth.inc index 5629f0c..3fb7ef4 100644 --- a/auth/services_keyauth/services_keyauth.inc +++ b/auth/services_keyauth/services_keyauth.inc @@ -1,5 +1,5 @@ 'checkbox', '#title' => t('Use keys'), '#default_value' => variable_get('services_use_key', TRUE), - '#description' => t('When enabled all method calls need to provide a validation token to autheciate themselves with the server.'), + '#description' => t('When enabled all method calls need to provide a validation token to authenticate themselves with the server.'), ); $form['services_key_expiry'] = array( '#type' => 'textfield', @@ -25,7 +25,7 @@ function _services_keyauth_security_settings() { '#type' => 'checkbox', '#title' => t('Use sessid'), '#default_value' => variable_get('services_use_sessid', TRUE), - '#description' => t('When enabled, all method calls must include a valid sessid. Only disable this setting if the application will user browser-based cookies.') + '#description' => t('When enabled, all method calls must include a valid sessid. Only disable this setting if the application will use browser-based cookies.') ); return $form; } @@ -51,76 +51,74 @@ function _services_keyauth_alter_methods(&$methods) { // sessid arg $arg_sessid = array( - '#name' => 'sessid', - '#type' => 'string', - '#description' => t('A valid sessid.'), + 'name' => 'sessid', + 'type' => 'string', + 'description' => t('A valid sessid.'), ); $arg_domain_time_stamp = array( - '#name' => 'domain_time_stamp', - '#type' => 'string', - '#description' => t('Time stamp used to hash key.'), + 'name' => 'domain_time_stamp', + 'type' => 'string', + 'description' => t('Time stamp used to hash key.'), ); $arg_nonce = array( - '#name' => 'nonce', - '#type' => 'string', - '#description' => t('One time use nonce also used hash key.'), + 'name' => 'nonce', + 'type' => 'string', + 'description' => t('One time use nonce also used hash key.'), ); // domain arg $arg_domain_name = array( - '#name' => 'domain_name', - '#type' => 'string', - '#description' => t('A valid domain for the API key.'), + 'name' => 'domain_name', + 'type' => 'string', + 'description' => t('A valid domain for the API key.'), ); // api_key arg $arg_api_key = array( - '#name' => 'hash', - '#type' => 'string', - '#description' => t('A valid API key.'), + 'name' => 'hash', + 'type' => 'string', + 'description' => t('A valid API key.'), ); foreach ($methods as $key => &$method) { // set method defaults - switch ($method['#method']) { + switch ($method['method']) { case 'system.connect': - case 'search.nodes': - case 'search.content': - case 'search.users': - $method['#key'] = FALSE; - $method['#auth'] = FALSE; + $method['key'] = FALSE; + $method['auth'] = FALSE; break; default: - $method['#key'] = TRUE; - $method['#auth'] = TRUE; + $method['key'] = isset($method['key']) ? FALSE : TRUE; + $method['auth'] = isset($method['auth']) ? FALSE : TRUE; + break; } - - if ($method['#auth'] && variable_get('services_use_sessid', TRUE)) { - array_unshift($method['#args'], $arg_sessid); + + if ($method['auth'] && variable_get('services_use_sessid', TRUE)) { + array_unshift($method['args'], $arg_sessid); } - if ($method['#key'] && variable_get('services_use_key', TRUE)) { - array_unshift($method['#args'], $arg_nonce); - array_unshift($method['#args'], $arg_domain_time_stamp); - array_unshift($method['#args'], $arg_domain_name); - array_unshift($method['#args'], $arg_api_key); + if ($method['key'] && variable_get('services_use_key', TRUE)) { + array_unshift($method['args'], $arg_nonce); + array_unshift($method['args'], $arg_domain_time_stamp); + array_unshift($method['args'], $arg_domain_name); + array_unshift($method['args'], $arg_api_key); } } } function _services_keyauth_alter_browse_form(&$form, $method) { - foreach ($method['#args'] as $key => $arg) { - switch ($arg['#name']) { + foreach ($method['args'] as $key => $arg) { + switch ($arg['name']) { case 'hash': $form['arg'][$key] = array( '#title' => 'Hash', '#type' => 'textfield', '#value' => t('Gets generated after form submission'), '#disabled' => TRUE - ); + ); break; case 'sessid': $form['arg'][$key]['#default_value'] = session_id(); @@ -130,11 +128,11 @@ function _services_keyauth_alter_browse_form(&$form, $method) { break; case 'domain_time_stamp': $form['arg'][$key] = array( - '#title' => 'Timestamp', - '#type' => 'textfield', - '#value' => t('Gets generated after form submission'), - '#disabled' => TRUE - ); + '#title' => 'Timestamp', + '#type' => 'textfield', + '#value' => t('Gets generated after form submission'), + '#disabled' => TRUE + ); break; case 'nonce': $form['arg'][$key]['#default_value'] = user_password(); @@ -144,7 +142,7 @@ function _services_keyauth_alter_browse_form(&$form, $method) { } function _services_keyauth_authenticate_call($method, $method_name, &$args) { - if ($method['#key'] && variable_get('services_use_key', TRUE)) { + if ($method['key'] && variable_get('services_use_key', TRUE)) { $hash = array_shift($args); $domain = array_shift($args); $timestamp = array_shift($args); @@ -160,7 +158,7 @@ function _services_keyauth_authenticate_call($method, $method_name, &$args) { if (db_result(db_query("SELECT count(*) FROM {services_timestamp_nonce} WHERE domain = '%s' AND nonce = '%s'", $domain, $nonce))) { - return services_error(t('Token has been used previously for a request. Re-try with another nonce key.', 401)); + return services_error(t('Token has been used previously for a request. Re-try with another nonce key.'), 401); } else{ db_query("INSERT INTO {services_timestamp_nonce} (domain, timestamp, nonce) @@ -173,8 +171,8 @@ function _services_keyauth_authenticate_call($method, $method_name, &$args) { if ($hash != services_get_hash($timestamp, $domain, $nonce, $method, $args)) { return services_error(t('Invalid API key.'), 401); } - - if (!db_result(db_query("SELECT COUNT(*) FROM {services_key_permissions} + + if (!db_result(db_query("SELECT COUNT(*) FROM {services_key_permissions} WHERE kid = '%s' AND method = '%s'", $api_key, $method_name))) { return services_error(t('Access denied.'), 401); } @@ -182,7 +180,7 @@ function _services_keyauth_authenticate_call($method, $method_name, &$args) { // Add additonal processing for methods requiring session $session_backup = NULL; - if ($method['#auth'] && variable_get('services_use_sessid', TRUE)) { + if ($method['auth'] && variable_get('services_use_sessid', TRUE)) { $sessid = array_shift($args); if (empty($sessid)) { return t('Invalid sessid.'); @@ -192,9 +190,9 @@ function _services_keyauth_authenticate_call($method, $method_name, &$args) { } function _services_keyauth_alter_browse_form_submit($method, &$args) { - if ($method['#key'] && variable_get('services_use_key', TRUE)) { + if ($method['key'] && variable_get('services_use_key', TRUE)) { $args_stripped = $args; - + for ($i = 1; $i <= 4; $i++) { array_shift($args_stripped); } diff --git a/auth/services_keyauth/services_keyauth.install b/auth/services_keyauth/services_keyauth.install index 64bcb31..74c993b 100644 --- a/auth/services_keyauth/services_keyauth.install +++ b/auth/services_keyauth/services_keyauth.install @@ -1,10 +1,11 @@ array('kid'), 'method' => array('method'), ), - 'unique key' => array('key_method' => array('kid','method')), + 'unique key' => array('key_method' => array('kid', 'method')), ); return $schema; } -function _services_key_auth_permissions (&$update) { +function _services_key_auth_permissions(&$update) { $schema['services_key_permissions'] = array( 'description' => t('Stores services method\'s access rights on a per API key basis.'), 'fields' => array( @@ -116,7 +117,7 @@ function _services_key_auth_permissions (&$update) { 'api_key' => array('kid'), 'method' => array('method'), ), - 'unique key' => array('key_method' => array('kid','method')), + 'unique key' => array('key_method' => array('kid', 'method')), ); db_create_table($update, 'services_key_permissions', $schema['services_key_permissions']); @@ -178,7 +179,7 @@ function services_keyauth_update_6004() { function services_keyauth_update_6005() { $update = array(); - + // A table might fail to exist in certain circumstances due to an issue with the install. if (!db_table_exists('services_key_permissions')) { _services_key_auth_permissions($update); diff --git a/auth/services_keyauth/services_keyauth.module b/auth/services_keyauth/services_keyauth.module index e18478a..d574873 100644 --- a/auth/services_keyauth/services_keyauth.module +++ b/auth/services_keyauth/services_keyauth.module @@ -1,7 +1,6 @@ 'services_keyauth.inc', - '#title' => t('Key authentication'), - '#description' => t('The default key-based authentication'), + 'file' => 'services_keyauth.inc', + 'title' => t('Key authentication'), + 'description' => t('The default key-based authentication'), 'security_settings' => '_services_keyauth_security_settings', 'security_settings_validate' => '_services_keyauth_security_settings_validate', 'security_settings_submit' => '_services_keyauth_security_settings_submit', @@ -94,11 +93,11 @@ function services_keyauth_menu() { } function services_get_hash($timestamp, $domain, $nonce, $method, $args) { - $hash_parameters = array($timestamp, $domain, $nonce, $method['#method']); - foreach ($method['#args'] as $key => $arg) { - if ($arg['#signed'] == TRUE) { + $hash_parameters = array($timestamp, $domain, $nonce, $method['method']); + foreach ($method['args'] as $key => $arg) { + if ($arg['signed'] == TRUE) { if (is_numeric($args[$key]) || !empty($args[$key])) { - if (is_array($args[$key]) || is_object($args[$key])){ + if (is_array($args[$key]) || is_object($args[$key])) { $hash_parameters[] = serialize($args[$key]); } else{ diff --git a/servers/xmlrpc_server/xmlrpc_server.module b/servers/xmlrpc_server/xmlrpc_server.module index 6d94f44..200ba34 100644 --- a/servers/xmlrpc_server/xmlrpc_server.module +++ b/servers/xmlrpc_server/xmlrpc_server.module @@ -1,7 +1,6 @@ '' ), ), - 'indexes' => array( - 'timestamp' => array('timestamp'), - ), + 'indexes' => array( + 'timestamp' => array('timestamp'), + ), 'primary key' => array('nonce'), ); $update = array(); diff --git a/services.module b/services.module index d44a28f..3077e86 100644 --- a/services.module +++ b/services.module @@ -1,10 +1,11 @@ '."\n"; $output .= ' '."\n"; $output .= ' '."\n"; - $keys = services_get_keys(); + $keys = (function_exists('services_keyauth_get_keys')) ? services_keyauth_get_keys() : array(); foreach ($keys as $key) { if (!empty($key->domain)) { @@ -155,6 +158,13 @@ function services_crossdomain_xml() { services_xml_output($output); } +/** + * Helper function for sending xml output. This method outputs a xml + * processing instruction and the necessary headers and then exits. + * + * @param string $xml + * @return void + */ function services_xml_output($xml) { $xml = ''."\n". $xml; header('Connection: close'); @@ -165,6 +175,15 @@ function services_xml_output($xml) { exit; } +/** + * Sets information about which server implementation that is used for the + * call. + * + * @param string $module + * The server module that's handling the call. + * @return object + * Server info object. + */ function services_set_server_info($module) { $server_info = new stdClass(); $server_info->module = $module; @@ -172,6 +191,15 @@ function services_set_server_info($module) { return services_get_server_info($server_info); } +/** + * Returns or sets the server info object. + * + * @param object $server_info + * Optional. Pass a object to set the server info object. Omit to just + * retrieve the server info. + * @return object + * Server info object. + */ function services_get_server_info($server_info = NULL) { static $info; if (!$info && $server_info) { @@ -180,12 +208,24 @@ function services_get_server_info($server_info = NULL) { return $info; } -/** - * Prepare an error message for returning to the server. - */ + /** + * Prepare an error message for returning to the server. + * + * @param string $message + * The error message. + * @param int $code + * Optional. A error code, these should map as closely to the applicable + * http error codes as closely as possible. + * @param Exception $exception + * Optional. The exception was thrown (if any) when the error occured. + * @return mixed + */ function services_error($message, $code = 0, $exception = NULL) { $server_info = services_get_server_info(); + // Allow external modules to log this error + module_invoke_all('services_error', $message, $code, $exception); + // Look for custom error handling function. // Should be defined in each server module. if ($server_info && module_hook($server_info->module, 'server_error')) { @@ -214,8 +254,8 @@ function services_auth_info($property = NULL, $module = NULL) { $module = $module ? $module : variable_get('services_auth_module', ''); if (!isset($info[$module])) { - if (!empty($module) && module_exists($module) && is_callable($module . '_authentication_info')) { - $info[$module] = call_user_func($module . '_authentication_info'); + if (!empty($module) && module_exists($module) && is_callable($module .'_authentication_info')) { + $info[$module] = call_user_func($module .'_authentication_info'); } else { $info[$module] = FALSE; @@ -231,13 +271,26 @@ function services_auth_info($property = NULL, $module = NULL) { return $info[$module]; } +/** + * Invokes a method for the configured authentication module. + * + * @param string $method + * The method to call. + * @param mixed $arg1 + * Optional. First argument. + * @param mixed $arg2 + * Optional. Second argument. + * @param mixed $arg3 + * Optional. Third argument. + * @return mixed + */ function services_auth_invoke($method, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NULL) { $module = variable_get('services_auth_module', ''); // Get information about the current auth module $func = services_auth_info($method, $module); if ($func) { - if ($file = services_auth_info('#file')) { - require_once(drupal_get_path('module', $module) . '/' . $file); + if ($file = services_auth_info('file')) { + require_once(drupal_get_path('module', $module) .'/'. $file); } if (is_callable($func)) { @@ -252,12 +305,27 @@ function services_auth_invoke($method, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NU } } +/** + * Invokes a method for the given authentication module. + * + * @param string $module + * The authentication module to call the method for. + * @param string $method + * The method to call. + * @param mixed $arg1 + * Optional. First argument. + * @param mixed $arg2 + * Optional. Second argument. + * @param mixed $arg3 + * Optional. Third argument. + * @return mixed + */ function services_auth_invoke_custom($module, $method, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NULL) { // Get information about the auth module $func = services_auth_info($method, $module); if ($func) { - if ($file = services_auth_info('#file', $module)) { - require_once(drupal_get_path('module', $module) . '/' . $file); + if ($file = services_auth_info('file', $module)) { + require_once(drupal_get_path('module', $module) .'/'. $file); } if (is_callable($func)) { @@ -273,10 +341,22 @@ function services_auth_invoke_custom($module, $method, &$arg1 = NULL, &$arg2 = N } /** - * This is the magic function through which all remote method calls must pass. + * Invokes a services method. + * + * @param mixed $method_name + * The method name or a method definition array. + * @param array $args + * Optional. An array containing arguments for the method. These arguments are not + * matched by name but by position. + * @param bool $browsing + * Optional. Whether the call was made by the services browser or not. + * @return mixed */ function services_method_call($method_name, $args = array(), $browsing = FALSE) { - if (is_array($method_name) && isset($method_name['#callback'])) { + // Allow external modules to log the results of this service call + module_invoke_all('services_method_call', $method_name, $args, $browsing); + + if (is_array($method_name) && isset($method_name['callback'])) { $method = $method_name; } else { @@ -290,8 +370,8 @@ function services_method_call($method_name, $args = array(), $browsing = FALSE) // Check for missing args $hash_parameters = array(); - foreach ($method['#args'] as $key => $arg) { - if (!$arg['#optional']) { + foreach ($method['args'] as $key => $arg) { + if (!$arg['optional']) { if (!isset($args[$key]) && !is_array($args[$key]) && !is_bool($args[$key])) { return services_error(t('Missing required arguments.'), 406); } @@ -299,7 +379,7 @@ function services_method_call($method_name, $args = array(), $browsing = FALSE) } // Check authentication - if ($auth_error = services_auth_invoke('authenticate_call', $method, $method_name, $args)) { + if ($method['auth'] && $auth_error = services_auth_invoke('authenticate_call', $method, $method_name, $args)) { if ($browsing) { drupal_set_message(t('Authentication failed: !message', array('!message' => $auth_error)), 'error'); } @@ -308,15 +388,17 @@ function services_method_call($method_name, $args = array(), $browsing = FALSE) } } - // Load the proper file - if ($file = $method['#file']) { - module_load_include($file['file'], $file['module']); + // Load the proper file. + if ($file = $method['file']) { + // Initialize file name if not given. + $file += array('file name' => ''); + module_load_include($file['file'], $file['module'], $file['file name']); } // Construct access arguments array - if (isset($method['#access arguments'])) { - $access_arguments = $method['#access arguments']; - if (isset($method['#access arguments append']) && $method['#access arguments append']) { + if (isset($method['access arguments'])) { + $access_arguments = $method['access arguments']; + if (isset($method['access arguments append']) && $method['access arguments append']) { $access_arguments[] = $args; } } @@ -326,7 +408,7 @@ function services_method_call($method_name, $args = array(), $browsing = FALSE) } // Call default or custom access callback - if (call_user_func_array($method['#access callback'], $access_arguments) != TRUE) { + if (call_user_func_array($method['access callback'], $access_arguments) != TRUE) { return services_error(t('Access denied'), 401); } @@ -337,11 +419,14 @@ function services_method_call($method_name, $args = array(), $browsing = FALSE) if ($server_info) { chdir($server_info->drupal_path); } - $result = call_user_func_array($method['#callback'], $args); + $result = call_user_func_array($method['callback'], $args); if ($server_info) { chdir($server_root); } + // Allow external modules to log the results of this service call + module_invoke_all('services_method_call_results', $method_name, $args, $browsing, $result); + return $result; } @@ -388,8 +473,8 @@ function services_resource_uri($path) { * @return array * An array containing all resources. */ -function services_get_all_resources($include_services = TRUE) { - $cache_key = 'services:resources' . ($include_services?'_with_services':''); +function services_get_all_resources($include_services = TRUE, $reset = FALSE) { + $cache_key = 'services:resources'. ($include_services?'_with_services':''); if (!$reset && ($cache = cache_get($cache_key)) && isset($cache->data)) { return $cache->data; @@ -397,21 +482,22 @@ function services_get_all_resources($include_services = TRUE) { else { $resources = module_invoke_all('service_resource'); drupal_alter('service_resources', $resources); + services_strip_hashes($resources); $controllers = array(); services_process_resources($resources, $controllers); foreach ($controllers as &$controller) { - if (!isset($controller['#access callback'])) { - $controller['#access callback'] = 'services_access_menu'; + if (!isset($controller['access callback'])) { + $controller['access callback'] = 'services_access_menu'; } - if (!isset($controller['#auth'])) { - $controller['#auth'] = TRUE; + if (!isset($controller['auth'])) { + $controller['auth'] = TRUE; } - if (!isset($controller['#key'])) { - $controller['#key'] = TRUE; + if (!isset($controller['key'])) { + $controller['key'] = TRUE; } } @@ -434,6 +520,36 @@ function services_get_all_resources($include_services = TRUE) { } } +/** + * Implementation of hook_form_alter(). + */ +function services_form_alter(&$form, $form_state, $form_id) { + if ($form_id == 'system_modules') { + // Add our own submit hook to clear cache + $form['#submit'][] = 'services_system_modules_submit'; + } +} + +/** + * Submit handler for the system_modules form that clears the services cache. + */ +function services_system_modules_submit($form, &$form_state) { + // Reset services cache + services_get_all(TRUE, TRUE); +} + +/** + * Processes the passed resources and adds all the controllers to the + * controller array. + * + * @param array $resources + * The resources that should be processed. + * @param string $controllers + * An array (passed by reference) that will be populated with the controllers + * of the passed resources. + * @param string $path + * Optional. Deprecated. + */ function services_process_resources(&$resources, &$controllers, $path=array()) { foreach ($resources as $name => &$resource) { if (drupal_substr($name, 0, 1) != '#') { @@ -442,60 +558,80 @@ function services_process_resources(&$resources, &$controllers, $path=array()) { } } +/** + * Processes a single resource and adds it's controllers to the controllers + * array. + * + * @param string $name + * The name of the resource. + * @param array $resource + * The resource definition. + * @param array $controllers + * An array (passed by reference) that will be populated with the controllers + * of the passed resources. + * @return void + */ function _services_process_resource($name, &$resource, &$controllers) { $path = join($name, '/'); - $resource['#name'] = $path; + $resource['name'] = $path; - $keys = array('#retrieve','#create','#update','#delete'); + $keys = array('retrieve', 'create', 'update', 'delete'); foreach ($keys as $key) { if (isset($resource[$key])) { - $controllers[$path . '/' . $key] = &$resource[$key]; + $controllers[$path .'/'. $key] = &$resource[$key]; } } - if (isset($resource['#index'])) { - $controllers[$path . '/#index'] = &$resource['#index']; + if (isset($resource['index'])) { + $controllers[$path .'/index'] = &$resource['index']; } - if (isset($resource['#relationships'])) { - foreach ($resource['#relationships'] as $relname => $rel) { + if (isset($resource['relationships'])) { + foreach ($resource['relationships'] as $relname => $rel) { // Run some inheritance logic - if (isset($resource['#retrieve'])) { - if (empty($rel['#args']) || $rel['#args'][0]['#name'] !== $resource['#retrieve']['#args'][0]['#name']) { - array_unshift($rel['#args'], $resource['#retrieve']['#args'][0]); + if (isset($resource['retrieve'])) { + if (empty($rel['args']) || $rel['args'][0]['name'] !== $resource['retrieve']['args'][0]['name']) { + array_unshift($rel['args'], $resource['retrieve']['args'][0]); } - $resource['#relationships'][$relname] = array_merge($resource['#retrieve'], $rel); + $resource['relationships'][$relname] = array_merge($resource['retrieve'], $rel); } - $controllers[$path . '/relationship/' . $relname] = &$resource['#relationships'][$relname]; + $controllers[$path .'/relationship/'. $relname] = &$resource['relationships'][$relname]; } } - if (isset($resource['#actions'])) { - foreach ($resource['#actions'] as $actname => $act) { + if (isset($resource['actions'])) { + foreach ($resource['actions'] as $actname => $act) { // Run some inheritance logic - if (isset($resource['#update'])) { - $up = $resource['#update']; - unset($up['#args']); - $resource['#actions'][$actname] = array_merge($up, $act); + if (isset($resource['update'])) { + $up = $resource['update']; + unset($up['args']); + $resource['actions'][$actname] = array_merge($up, $act); } - $controllers[$path . '/action/' . $actname] = &$resource['#actions'][$actname]; + $controllers[$path .'/action/'. $actname] = &$resource['actions'][$actname]; } } - if (isset($resource['#targeted actions'])) { - foreach ($resource['#targeted actions'] as $actname => $act) { + if (isset($resource['targeted actions'])) { + foreach ($resource['targeted actions'] as $actname => $act) { // Run some inheritance logic - if (isset($resource['#update'])) { - if (empty($act['#args']) || $act['#args'][0]['#name'] !== $resource['#update']['#args'][0]['#name']) { - array_unshift($act['#args'], $resource['#update']['#args'][0]); + if (isset($resource['update'])) { + if (empty($act['args']) || $act['args'][0]['name'] !== $resource['update']['args'][0]['name']) { + array_unshift($act['args'], $resource['update']['args'][0]); } - $resource['#targeted actions'][$actname] = array_merge($resource['#update'], $act); + $resource['targeted actions'][$actname] = array_merge($resource['update'], $act); } - $controllers[$path . '/targeted_action/' . $actname] = &$resource['#actions'][$actname]; + $controllers[$path .'/targeted_action/'. $actname] = &$resource['actions'][$actname]; } } } +/** + * Should be removed. This code doesn't seem to be used anywhere. + * + * @param string $perm + * The permission to check for. + * @return bool + */ function services_delegate_access($perm) { return services_auth_invoke('delegate_access', $perm); } @@ -510,42 +646,43 @@ function services_delegate_access($perm) { * @return array * An array containing all services and thir methods */ -function services_get_all($include_resources = TRUE) { - $cache_key = 'services:methods' . ($include_resources?'_with_resources':''); +function services_get_all($include_resources = TRUE, $reset = FALSE) { + $cache_key = 'services:methods'. ($include_resources?'_with_resources':''); - if (($cache = cache_get($cache_key)) && isset($cache->data)) { + if (!$reset && ($cache = cache_get($cache_key)) && isset($cache->data)) { return $cache->data; } else { $methods = module_invoke_all('service'); + services_strip_hashes($methods); foreach ($methods as $key => $method) { - if (!isset($methods[$key]['#access callback'])) { - $methods[$key]['#access callback'] = 'services_access_menu'; + if (!isset($methods[$key]['access callback'])) { + $methods[$key]['access callback'] = 'services_access_menu'; } - if (!isset($methods[$key]['#args'])) { - $methods[$key]['#args'] = array(); + if (!isset($methods[$key]['args'])) { + $methods[$key]['args'] = array(); } // set defaults for args - foreach ($methods[$key]['#args'] as $arg_key => $arg) { + foreach ($methods[$key]['args'] as $arg_key => $arg) { if (is_array($arg)) { - if (!isset($arg['#optional'])) { - $methods[$key]['#args'][$arg_key]['#optional'] = FALSE; + if (!isset($arg['optional'])) { + $methods[$key]['args'][$arg_key]['optional'] = FALSE; } } else { $arr_arg = array(); - $arr_arg['#name'] = t('unnamed'); - $arr_arg['#type'] = $arg; - $arr_arg['#description'] = t('No description given.'); - $arr_arg['#optional'] = FALSE; - $methods[$key]['#args'][$arg_key] = $arr_arg; + $arr_arg['name'] = t('unnamed'); + $arr_arg['type'] = $arg; + $arr_arg['description'] = t('No description given.'); + $arr_arg['optional'] = FALSE; + $methods[$key]['args'][$arg_key] = $arr_arg; } } - reset($methods[$key]['#args']); + reset($methods[$key]['args']); } // Allow auth module to alter the methods @@ -553,7 +690,7 @@ function services_get_all($include_resources = TRUE) { // Add resources if wanted if ($include_resources) { - $resources = services_get_all_resources(FALSE); + $resources = services_get_all_resources(FALSE, $reset); // Include the file that has the necessary functions for translating // resources to method calls. @@ -562,7 +699,7 @@ function services_get_all($include_resources = TRUE) { // Translate all resources foreach ($resources as $name => $def) { - foreach(_services_resource_as_services($def) as $method) { + foreach (_services_resource_as_services($def) as $method) { $methods[] = $method; } } @@ -582,11 +719,19 @@ function services_method_load($method) { return isset($method) ? $method : FALSE; } +/** + * Get's the definition of a method. + * + * @param string $method_name + * The name of the method to get the definition for. + * @return array + * The method definition. + */ function services_method_get($method_name) { static $method_cache; if (!isset($method_cache[$method_name])) { foreach (services_get_all() as $method) { - if ($method_name == $method['#method']) { + if ($method_name == $method['method']) { $method_cache[$method_name] = $method; break; } @@ -596,7 +741,34 @@ function services_method_get($method_name) { } /** - * Make any changes we might want to make to node. + * Cleanup function to remove unnecessary hashes from service definitions. + * + * @param array $array + * A service definition or an array of service definitions. + * @return void + */ +function services_strip_hashes(&$array) { + foreach ($array as $key => $value) { + if (is_array($value)) { + services_strip_hashes($array[$key]); + } + if (strpos($key, '#') === 0) { + $array[substr($key, 1)] = $array[$key]; + unset($array[$key]); + } + } +} + +/** + * Creates an object that only contains the specified attributes from the node + * object. + * + * @param object $node + * The node to get the attributes. + * @param array $fields + * An array containing the names of the attributes to get. + * @return object + * An object with the specified attributes. */ function services_node_load($node, $fields = array()) { if (!isset($node->nid)) { @@ -688,4 +860,4 @@ function services_session_unload($backup) { */ function services_access_menu() { return TRUE; -} \ No newline at end of file +} diff --git a/services.resource-translation.inc b/services.resource-translation.inc index 8b990eb..ecbbc45 100644 --- a/services.resource-translation.inc +++ b/services.resource-translation.inc @@ -1,73 +1,101 @@ 'create', - '#delete' => 'delete', - '#retrieve' => 'retrieve', - '#update' => 'update', - '#index' => 'index', + 'create' => 'create', + 'delete' => 'delete', + 'retrieve' => 'retrieve', + 'update' => 'update', + 'index' => 'index', ), $subcontrollers = array( - '#relationships' => 'related', - '#targeted actions' => 'targeted_action', + 'relationships' => 'related', + 'targeted actions' => 'targeted_action', ); $methods = array(); - $file = isset($resource['#file']) ? $resource['#file'] : array(); + $file = isset($resource['file']) ? $resource['file'] : array(); foreach ($controllers as $attr => $name) { if (isset($resource[$attr])) { - $methods[] = _services_resource_controller_as_service($resource['#name'], $name, $resource[$attr], $file); + $methods[] = _services_resource_controller_as_service($resource['name'], $name, $resource[$attr], $file); } } foreach ($subcontrollers as $attr => $name) { if (isset($resource[$attr])) { foreach ($resource[$attr] as $sc_name => $controller) { - $methods[] = _services_resource_controller_as_service($resource['#name'], $name . '_' . $sc_name, $controller, $file); + $methods[] = _services_resource_controller_as_service($resource['name'], $name .'_'. $sc_name, $controller, $file); } } } - if (isset($resource['#actions'])) { - foreach ($resource['#actions'] as $sc_name => $controller) { - $methods[] = _services_resource_controller_as_service($resource['#name'], 'action_' . $sc_name, $controller, $file); + if (isset($resource['actions'])) { + foreach ($resource['actions'] as $sc_name => $controller) { + $methods[] = _services_resource_controller_as_service($resource['name'], 'action_'. $sc_name, $controller, $file); } } return $methods; } +/** + * Helper function for _services_resource_as_services() that turns a resource + * controller into a service method. + */ function _services_resource_controller_as_service($resource, $name, $controller, $file) { $method = array_merge($controller, array( - '#method' => $resource . '_resource.' . $name, + 'method' => $resource .'_resource.'. $name, )); - if (!empty($file) && !empty($method['#file'])) { - $method['#file'] = $file; + if (!empty($file) && !empty($method['file'])) { + $method['file'] = $file; } return $method; } +/** + * Turns an array of services methods into resources where all methods are + * added as actions. A 'menu.get'-method would be added as a 'get'-action on + * the resource 'service_menu'. + * + * @param array $services + * An array of service methods. + * @return array + * An array of resource definitions. + */ function _services_services_as_resources($services) { $resources = array(); foreach ($services as $service) { - $signature = preg_split('/\./', $service['#method']); + $signature = preg_split('/\./', $service['method']); $controller = $service; - $controller['#args'] = array(); + $controller['args'] = array(); - foreach($service['#args'] as $arg) { - $arg['#source'] = array( - 'data' => $arg['#name'], + foreach ($service['args'] as $arg) { + $arg['source'] = array( + 'data' => $arg['name'], ); - $controller['#args'][] = $arg; + $controller['args'][] = $arg; } - $resources['service_' . $signature[0]]['#actions'][$signature[1]] = $controller; + $resources['service_'. $signature[0]]['actions'][$signature[1]] = $controller; } return $resources; -} \ No newline at end of file +} diff --git a/services/comment_service/comment_service.inc b/services/comment_service/comment_service.inc index 06e15bf..4de7e57 100644 --- a/services/comment_service/comment_service.inc +++ b/services/comment_service/comment_service.inc @@ -1,7 +1,7 @@ cid then that comment is edited. * * @param $comment - * An array matching the form values that would be submitted in the comment + * An array matching the form values that would be submitted in the comment * edit form. * @return * Unique identifier for the comment (cid) or FALSE if there was a problem. @@ -78,7 +78,7 @@ function comment_service_load_node_comments($nid, $count = 0, $start = 0) { * @param $cid * Unique identifier for the specified comment * @return - * The comment object + * The comment object */ function comment_service_load($cid) { $cid = db_result(db_query("SELECT cid FROM {comments} WHERE cid = %d", $cid)); diff --git a/services/comment_service/comment_service.module b/services/comment_service/comment_service.module index 4bed2d2..2538c95 100644 --- a/services/comment_service/comment_service.module +++ b/services/comment_service/comment_service.module @@ -1,7 +1,7 @@ 'comment.save', @@ -67,7 +67,7 @@ function comment_service_service() { array( '#name' => 'start', '#type' => 'int', - '#description' => t('If count is set to non-zero value, You can pass also non-zero value for start. For example to get comments from 5 to 15, pass count=10 and start=5.'), + '#description' => t('If count is set to non-zero value, you can pass also non-zero value for start. For example to get comments from 5 to 15, pass count=10 and start=5.'), ), ), '#return' => 'array', @@ -130,12 +130,4 @@ function comment_service_service() { '#help' => t('This method returns the number of new comments on a given node since a given timestamp.'), ), ); -} - -function comments_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function comments_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services/file_service/file_service.inc b/services/file_service/file_service.inc index eb70646..bc7541e 100644 --- a/services/file_service/file_service.inc +++ b/services/file_service/file_service.inc @@ -1,7 +1,7 @@ file)) { + return FALSE; + } + + // If the submitted file is an update, then set the update parameter for + // drupal_write_record(), indicating such. Otherwise we can just pass the + // object in and it will be treated as an insert. + $update = array(); + if (!empty($file->fid)) { + $update = 'fid'; + } + + // Build the list of non-munged extensions. + // @todo: this should not be here. we need to figure out the right place. + // @todo: also isn't that repeated variable get a waste? I mean, I guess it + // is cached but still it is pretty ugly. + $extensions = ''; + foreach ($user->roles as $rid => $name) { + $extensions .= ' '. variable_get("upload_extensions_$rid", + variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp')); + } + + // Get the directory name for the location of the file: + $dir = dirname($file->filepath); + // Build the destination folder tree if it doesn't already exists. + if (!file_check_directory($dir, FILE_CREATE_DIRECTORY)) { + return services_error("Could not create destination directory for file."); + } + + // Update file object as necessary + $file->filepath = file_destination(file_create_path($file->filepath), FILE_EXISTS_RENAME); + $file->filename = file_munge_filename(trim(basename($file->filepath), '.'), $extensions, TRUE); + $file->filemime = file_get_mimetype($file->filename); + + // Rename potentially executable files, to help prevent exploits. + if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { + $file->filemime = 'text/plain'; + $file->filepath .= '.txt'; + $file->filename .= '.txt'; + } + + // If the destination is not provided, or is not writable, error our + if (empty($file->filepath) || file_check_path($file->filepath) === FALSE) { + return services_error("Destintion directory does not exist or is not writeable."); + } + + //The filepath that ends up in the node must contain the filename + $file->filepath .= '/'. $file->filename; + + // Write the file + if (!file_save_data(base64_decode($file->file), $file->filepath)) { + return services_error("Could not write file to destination"); + } + + // If we made it this far it's safe to record this file in the database. + drupal_write_record('files', $file, $update); + + // hook_file_insert() requires an object + if (empty($update)) { + foreach (module_implements('file_insert') as $module) { + $function = $module .'_file_insert'; + $function($file); + } + } + + // Return the fid + return $file->fid; +} + /** * Check if the user has permission to get a given file */ diff --git a/services/file_service/file_service.module b/services/file_service/file_service.module index e28bd10..d4204a8 100644 --- a/services/file_service/file_service.module +++ b/services/file_service/file_service.module @@ -1,7 +1,6 @@ 'array', '#help' => t('Returns the files attached to a node.') ), - ); -} - -function file_service_disable() { - cache_clear_all('services:methods', 'cache'); -} -function file_service_enable() { - cache_clear_all('services:methods', 'cache'); + // file.save + array( + '#method' => 'file.save', + '#callback' => 'file_service_save', + '#access arguments' => 'save file information', + '#file' => array('file' => 'inc', 'module' => 'file_service'), + '#args' => array( + array( + '#name' => 'file', + '#type' => 'struct', + '#description' => t('An object representing a file.'), + ), + ), + '#return' => 'int', + '#help' => t('Saves information about a specific file. Note this does not save files themselves, just the information as stored in the files table. Returns the fid of the new/updated file.'), + ), + ); } \ No newline at end of file diff --git a/services/menu_service/menu_service.inc b/services/menu_service/menu_service.inc index 150ecb3..221b1bf 100644 --- a/services/menu_service/menu_service.inc +++ b/services/menu_service/menu_service.inc @@ -1,5 +1,5 @@ path_alias = drupal_get_path_alias($tmp->link_path); + $tmp->path_alias = drupal_get_path_alias($item['link']['link_path']); } $tmp->children = menu_service_process($item['below'], $fields); $out[] = $tmp; diff --git a/services/menu_service/menu_service.module b/services/menu_service/menu_service.module index cbe8db2..5186e06 100644 --- a/services/menu_service/menu_service.module +++ b/services/menu_service/menu_service.module @@ -1,5 +1,5 @@ type . '_node_form', $form_state, $node); + $ret = drupal_execute($node->type .'_node_form', $form_state, $node); // Fetch $nid out of $form_state $nid = $form_state['nid']; @@ -54,7 +59,7 @@ function _node_resource_update($nid, $node) { $form_state['values']['op'] = t('Save'); $form_state['node'] = (array)$old_node; - drupal_execute($old_node->type . '_node_form', $form_state, $old_node); + drupal_execute($old_node->type .'_node_form', $form_state, $old_node); if ($errors = form_get_errors()) { return services_error(implode("\n", $errors), 406); diff --git a/services/node_service/node_resource.models.inc b/services/node_service/node_resource.models.inc index 40528aa..827b6ba 100644 --- a/services/node_service/node_resource.models.inc +++ b/services/node_service/node_resource.models.inc @@ -1,5 +1,10 @@ node->nid, array('absolute' => TRUE)); + return url('node/'. $this->node->nid, array('absolute' => TRUE)); } /** diff --git a/services/node_service/node_resource.module b/services/node_service/node_resource.module index 2e3ea64..fee6ea3 100644 --- a/services/node_service/node_resource.module +++ b/services/node_service/node_resource.module @@ -1,5 +1,10 @@ array( - '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#retrieve' => array( '#callback' => '_node_resource_retrieve', + '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#args' => array( array( '#name' => 'nid', @@ -39,6 +44,7 @@ function node_resource_service_resource() { ), '#create' => array( '#callback' => '_node_resource_create', + '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#args' => array( array( '#name' => 'node', @@ -54,6 +60,7 @@ function node_resource_service_resource() { ), '#update' => array( '#callback' => '_node_resource_update', + '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#args' => array( array( '#name' => 'node', @@ -69,6 +76,7 @@ function node_resource_service_resource() { ), '#delete' => array( '#callback' => '_node_resource_delete', + '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#args' => array( array( '#name' => 'nid', @@ -82,6 +90,7 @@ function node_resource_service_resource() { ), '#index' => array( '#callback' => '_node_resource_index', + '#file' => array('file' => 'inc', 'module' => 'node_resource'), '#args' => array( array( '#name' => 'page', diff --git a/services/node_service/node_service.inc b/services/node_service/node_service.inc index 161dcbc..eea271c 100644 --- a/services/node_service/node_service.inc +++ b/services/node_service/node_service.inc @@ -1,7 +1,7 @@ t('A node ID.'))), '#help' => t('Delete a node.')), ); -} - -function node_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function node_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services/search_service/search_service.inc b/services/search_service/search_service.inc index 67a2101..31ef4a8 100644 --- a/services/search_service/search_service.inc +++ b/services/search_service/search_service.inc @@ -1,7 +1,6 @@ 'node')); - watchdog('search_service', t('search.content invoked for !keys using hooks !hooks', array('!keys' => $keys, '!hooks' => implode($search_hooks, ', ')))); + watchdog('search_service', t('search.content invoked for !keys using hooks !hooks', array('!keys' => $keys, '!hooks' => implode(', ', $search_hooks)))); // run through only select hook_search() as defined in /admin/settings/search_service foreach ($search_hooks as $hook) { diff --git a/services/search_service/search_service.module b/services/search_service/search_service.module index 8b58a5e..dc95680 100644 --- a/services/search_service/search_service.module +++ b/services/search_service/search_service.module @@ -1,7 +1,6 @@ t('Searches users according to keys via hook_search.'), ) ); -} - -function search_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function search_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services/system_service/system_service.inc b/services/system_service/system_service.inc index db261d0..59549b2 100644 --- a/services/system_service/system_service.inc +++ b/services/system_service/system_service.inc @@ -1,7 +1,6 @@ 'bool', '#help' => t('Clear cache on remote site.'), ), - ); -} -function system_service_disable() { - cache_clear_all('services:methods', 'cache'); + // system.watchdog + array( + '#method' => 'system.watchdog', + '#callback' => 'system_service_watchdog_send', + '#access arguments' => array('log a system message from remote'), + '#file' => array('file' => 'inc', 'module' => 'system_service'), + '#args' => array( + array( + '#name' => 'type', + '#type' => 'string', + '#description' => t('The category to which this message belongs.') + ), + array( + '#name' => 'message', + '#type' => 'string', + '#description' => t('The message to store in the log. See t() for documentation on how $message and $variables interact. Keep $message translatable by not concatenating dynamic values into it!') + ), + array( + '#name' => 'variables', + '#type' => 'array', + '#optional' => TRUE, + '#description' => t('Array of variables to replace in the message on display or NULL if message is already translated or not possible to translate.') + ), + array( + '#name' => 'severity', + '#type' => 'int', + '#optional' => TRUE, + '#description' => t('The severity of the message, as per RFC 3164.') + ), + array( + '#name' => 'link', + '#type' => 'string', + '#optional' => TRUE, + '#description' => t('A link to associate with the message.') + ), + ), + '#return' => 'bool', + '#help' => t('Log a system message.'), + ), + ); } - -function system_service_enable() { - cache_clear_all('services:methods', 'cache'); -} \ No newline at end of file diff --git a/services/taxonomy_service/taxonomy_service.inc b/services/taxonomy_service/taxonomy_service.inc index 9dd2740..54b0286 100644 --- a/services/taxonomy_service/taxonomy_service.inc +++ b/services/taxonomy_service/taxonomy_service.inc @@ -1,7 +1,6 @@ 'taxonomy.saveTerm', '#callback' => 'taxonomy_service_save_term', + '#access arguments' => array('administer taxonomy from remote'), '#file' => array('file' => 'inc', 'module' => 'taxonomy_service'), '#args' => array( array( @@ -43,6 +50,7 @@ function taxonomy_service_service() { array( '#method' => 'taxonomy.saveVocabulary', '#callback' => 'taxonomy_service_save_vocabulary', + '#access arguments' => array('administer taxonomy from remote'), '#file' => array('file' => 'inc', 'module' => 'taxonomy_service'), '#args' => array( array( @@ -129,12 +137,4 @@ function taxonomy_service_service() { '#help' => t('Finds all nodes that match selected taxonomy conditions.') ), ); -} - -function taxonomy_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function taxonomy_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services/user_service/user_service.inc b/services/user_service/user_service.inc index 8f92e4d..1d9ff7a 100644 --- a/services/user_service/user_service.inc +++ b/services/user_service/user_service.inc @@ -1,7 +1,7 @@ uid) ? user_save($update,$account) : user_save('', $account); - if (!$account) { - return services_error(t('Error on saving the user.'), 500); + $form_state = array(); + if (!isset($update->uid)) { + // register a new user + $form_state['values'] = $account; + $form_state['values']['pass'] = array( + 'pass1' => $account['pass'], + 'pass2' => $account['pass'], + ); + $form_state['values']['op'] = t('Create new account'); + $ret = drupal_execute('user_register', $form_state); + } + else { + // If a profile category was passed in, use it. Otherwise default + // to 'account' (for saving core user data.) + $category = 'account'; + if (isset($account['category'])) { + $category = $account['category']; + unset($account['category']); + } + + // Any logged in user is by default authenticated, + // and leaving this role set in the user's roles array + // causes big problems because of a FAPI hack that controls + // this checkbox. Therefore we just force it to 0 here. + if (isset($account['roles'][2])) { + $account['roles'][2] = 0; + } + + // Drop any passed in values into the $account var. Anything + // unused by the form just gets ignored. + foreach ($account as $key => $value) { + $form_state['values'][$key] = $value; + } + + $form_state['values']['op'] = 'Save'; + $form_state['values']['_category'] = $category; + $form_state['values']['_account'] = $account; + $ret = drupal_execute('user_profile_form', $form_state, (object) $account, $category); } - // Everything went right. - // Return the user ID - return $account->uid; + // Error if needed. + if ($errors = form_get_errors()) { + return services_error(implode("\n", $errors), 401); + } + else { + return $form_state['user']->uid; + } } /** diff --git a/services/user_service/user_service.module b/services/user_service/user_service.module index f64a3a5..64a30e4 100644 --- a/services/user_service/user_service.module +++ b/services/user_service/user_service.module @@ -1,7 +1,6 @@ t('Save user details.') ), ); -} - -function user_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function user_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services/views_service/views_service.inc b/services/views_service/views_service.inc index a3d0dad..8514239 100644 --- a/services/views_service/views_service.inc +++ b/services/views_service/views_service.inc @@ -1,7 +1,6 @@ set_arguments($args, FALSE); $view->set_offset($offset); - $view->set_items_per_page($limit); - $view->execute(); - - // Get row plugin setting - $row_plugin = $view->display[$view->current_display]->display_options['row_plugin']; - - $nodes = array(); - // If row plugin is node, then we must do a node_load - if ($row_plugin == 'node') { - foreach ($view->result as $node) { - $nodes[] = services_node_load(node_load($node->nid), $fields); - } + // If offset is set we can't have a user pager. + if (empty($offset)) { + $view->set_use_pager(TRUE); + $view->set_items_per_page($limit); } - // Otherwise, pass through the fields filter, just in case else { - foreach ($view->result as $node) { - $nodes[] = services_node_load($node, $fields); - } + // Disable the user pager. + $view->set_use_pager(FALSE); } - - return $nodes; + if (!$format_output) { + $view->set_display($display_id); + $view->execute(); + $result = $view->result; + } + else { + // We want to keep the result an array. + $result[] = $view->preview($display_id); + } + return $result; } /** diff --git a/services/views_service/views_service.module b/services/views_service/views_service.module index b5e1deb..71e5104 100644 --- a/services/views_service/views_service.module +++ b/services/views_service/views_service.module @@ -1,7 +1,6 @@ t('View name.') ), array( - '#name' => 'fields', - '#type' => 'array', + '#name' => 'display_id', + '#type' => 'string', '#optional' => TRUE, - '#description' => t('A list of fields to return.') + '#description' => t('A display provided by the selected view.') ), array( '#name' => 'args', @@ -51,13 +50,19 @@ function views_service_service() { '#name' => 'offset', '#type' => 'int', '#optional' => TRUE, - '#description' => t('An offset integer for paging.') + '#description' => t('An offset integer for paging. If this is set limit will be ignored.') ), array( '#name' => 'limit', '#type' => 'int', '#optional' => TRUE, - '#description' => t('A limit integer for paging.') + '#description' => t('A limit integer for paging. If offset is set, this will be ignored.') + ), + array( + '#name' => 'format_output', + '#type' => 'boolean', + '#optional' => TRUE, + '#description' => t('TRUE if view should be formatted, or only the view result returned (FALSE by default).') ), ), '#return' => 'array', @@ -106,12 +111,4 @@ function views_service_service() { '#help' => t('Imports a view through code, equivalent to using the Import tab in the views admin.'), ), ); -} - -function views_service_disable() { - cache_clear_all('services:methods', 'cache'); -} - -function views_service_enable() { - cache_clear_all('services:methods', 'cache'); } \ No newline at end of file diff --git a/services_admin_browse.inc b/services_admin_browse.inc index 393781d..59eea4a 100644 --- a/services_admin_browse.inc +++ b/services_admin_browse.inc @@ -1,13 +1,15 @@ '; foreach ($servers as $module) { $info = module_invoke($module, 'server_info'); - $name = $info['#name']; - $path = 'services/'. $info['#path']; + services_strip_hashes($info); + + $name = $info['name']; + $path = 'services/'. $info['path']; $output .= '
  • '. l($name .' - /'. $path, $path) .'
  • '; } $output .= ''; @@ -36,7 +40,7 @@ function services_admin_browse_index() { // group namespaces $services = array(); foreach ($methods as $method) { - $namespace = drupal_substr($method['#method'], 0, strrpos($method['#method'], '.')); + $namespace = drupal_substr($method['method'], 0, strrpos($method['method'], '.')); $services[$namespace][] = $method; } @@ -45,7 +49,7 @@ function services_admin_browse_index() { $output .= '

    '. $namespace .'

    '; $output .= ''; } @@ -57,23 +61,31 @@ function services_admin_browse_index() { return $output; } +/** + * Display a form for the testing of a single service method in the browser. + * + * @param $method + * The method to be tested + * @return + * Form for testing and method parameter info. + */ function services_admin_browse_method($method) { global $_services_admin_browse_test_submit_result; $output = ''; - $output .= '

    '. $method['#method'] .'

    '; - $output .= '

    '. $method['#help'] .'

    '; + $output .= '

    '. $method['method'] .'

    '; + $output .= '

    '. $method['help'] .'

    '; // List arguments. - $output .= '

    '. t('Arguments') .' ('. count($method['#args']) .')

    '; + $output .= '

    '. t('Arguments') .' ('. count($method['args']) .')

    '; $output .= '
    '; $count = 0; - foreach ($method['#args'] as $arg) { + foreach ($method['args'] as $arg) { $count++; - $output .= '
    '. $arg['#type'] .''. - $arg['#name'] .' ('. (($arg['#optional']) ? t('optional') : t('required')) .')
    '; - $output .= '
    '. $arg['#description'] .'
    '; + $output .= '
    '. $arg['type'] .''. + $arg['name'] .' ('. (($arg['optional']) ? t('optional') : t('required')) .')
    '; + $output .= '
    '. $arg['description'] .'
    '; } $output .= '
    '; @@ -93,6 +105,14 @@ function services_admin_browse_method($method) { return $output; } +/** + * Build the form used for testing a service in the browser + * + * @return + * FAPI array + * @ingroup forms + * @see services_admin_browse_test_submit() + */ function services_admin_browse_test() { $form = array(); $method = services_method_get(arg(4)); @@ -100,15 +120,15 @@ function services_admin_browse_test() { $form['arg'] = array('#tree' => TRUE); $form['format'] = array('#tree' => TRUE); - foreach ($method['#args'] as $key => $arg) { + foreach ($method['args'] as $key => $arg) { $form['name'][$key] = array( - '#value' => $arg['#name'] + '#value' => $arg['name'] ); $form['optional'][$key] = array( - '#value' => ($arg['#optional']) ? t('optional') : t('required') + '#value' => ($arg['optional']) ? t('optional') : t('required') ); - if (isset($arg['#size']) && $arg['#size'] == 'big') { + if (isset($arg['size']) && $arg['size'] == 'big') { $form['arg'][$key] = array( '#type' => 'textarea' ); @@ -120,7 +140,7 @@ function services_admin_browse_test() { } $format_opt = array(); - switch ($arg['#type']) { + switch ($arg['type']) { case 'array': $format_opt['cdel'] = t('Comma delimited'); case 'struct': @@ -153,13 +173,16 @@ function services_admin_browse_test() { return $form; } +/** + * Submit callback for services_admin_browse_test(). + */ function services_admin_browse_test_submit($form, $form_state) { global $_services_admin_browse_test_submit_result; $method = services_method_get(arg(4)); $args = services_admin_browse_test_unserialize_args($form_state['values']['arg'], $form_state['values']['format']); // Allow the authorization module to handle submitted values. services_auth_invoke('alter_browse_form_submit', $method, $args); - $result = services_method_call($method['#method'], $args, TRUE); + $result = services_method_call($method['method'], $args, TRUE); $_services_admin_browse_test_submit_result = '
    '. htmlspecialchars(print_r($result, TRUE)) .'
    '; } @@ -167,8 +190,8 @@ function services_admin_browse_test_unserialize_args($values, $formats) { $method = services_method_get(arg(4)); $noskip = FALSE; // Convert args - for ($c = count($method['#args']) - 1; $c >= 0; $c--) { - $arg = $method['#args'][$c]; + for ($c = count($method['args']) - 1; $c >= 0; $c--) { + $arg = $method['args'][$c]; $value = $values[$c]; // Remove empty values from end of array @@ -192,7 +215,7 @@ function services_admin_browse_test_unserialize_args($values, $formats) { $return[$c] = NULL; } else { - $return[$c] = json_decode($value, $arg['#type'] === 'array'); + $return[$c] = json_decode($value, $arg['type'] === 'array'); } break; case 'sphp': @@ -212,7 +235,9 @@ function services_admin_browse_test_unserialize_args($values, $formats) { return $return; } - +/** + * Implementation of hook_theme(); + */ function theme_services_admin_browse_test($form) { $output = ''; $output .= drupal_render($form['test']); @@ -243,8 +268,13 @@ function theme_services_admin_browse_test($form) { return $output; } -/* - * Callback for admin page +/** + * Build the admin settings form. + * + * @return + * FAPI array + * @ingroup forms + * @see services_admin_settings_submit() */ function services_admin_settings() { $auth_modules = module_implements('authentication_info'); @@ -254,7 +284,9 @@ function services_admin_settings() { $auth_options = array('' => t('-- Select a authorization module')); foreach ($auth_modules as $module) { $info = services_auth_info(NULL, $module); - $auth_options[$info['#description']][$module] = $info['#title']; + services_strip_hashes($info); + + $auth_options[$info['description']][$module] = $info['title']; } $form['security'] = array( @@ -304,6 +336,9 @@ function services_admin_settings() { return $form; } +/** + * Validate callback for services_admin_settings(). + */ function services_admin_settings_validate($form, $form_state) { // Invoke custom validation for the auth module if (!empty($form_state['values']['auth_module'])) { @@ -312,6 +347,9 @@ function services_admin_settings_validate($form, $form_state) { } } +/** + * Submit callback for services_admin_settings(). + */ function services_admin_settings_submit($form, $form_state) { // Update the services oauth module variable *if needed*. $old_auth = variable_get('services_auth_module', '');