Skip to content

Instantly share code, notes, and snippets.

@arturo-c
Created November 28, 2011 21:30
Show Gist options
  • Save arturo-c/1402160 to your computer and use it in GitHub Desktop.
Save arturo-c/1402160 to your computer and use it in GitHub Desktop.
diff --git a/plugins/export_ui/services_ctools_export_ui.class.php b/plugins/export_ui/services_ctools_export_ui.class.php
index fe4a51d..99de0c4 100644
--- a/plugins/export_ui/services_ctools_export_ui.class.php
+++ b/plugins/export_ui/services_ctools_export_ui.class.php
@@ -23,6 +23,14 @@ class services_ctools_export_ui extends ctools_export_ui {
return drupal_get_form('services_edit_form_endpoint_authentication', $item);
}
+ /**
+ * Page callback for the server page.
+ */
+ function server_page($js, $input, $item) {
+ drupal_set_title($this->get_page_title('server', $item));
+ return drupal_get_form('services_edit_form_endpoint_server', $item);
+ }
+
// Avoid standard submit of edit form by ctools.
function edit_save_form($form_state) { }
@@ -58,8 +66,7 @@ function services_edit_form_endpoint_authentication($form_state) {
$form['message'] = array(
'#type' => 'item',
'#title' => t('Authentication'),
- '#description' => t('No authentication modules are installed, standard ' .
- 'Drupal session based security will be used.'),
+ '#description' => t('No authentication modules are installed, all requests will be anonymous.'),
);
return $form;
}
@@ -67,8 +74,7 @@ function services_edit_form_endpoint_authentication($form_state) {
$form['message'] = array(
'#type' => 'item',
'#title' => t('Authentication'),
- '#description' => t('No authentication modules are enabled, standard ' .
- 'Drupal session based security will be used.'),
+ '#description' => t('No authentication modules are enabled, all requests will be anonymous.'),
);
return $form;
}
@@ -115,6 +121,79 @@ function services_edit_form_endpoint_authentication_submit($form, $form_state) {
services_endpoint_save($endpoint);
}
+function services_edit_form_endpoint_server($form, $form_state) {
+ $form = array();
+ $endpoint = $form_state;
+ $servers = services_get_servers();
+
+ $server = !empty($servers[$endpoint->server]) ? $servers[$endpoint->server] : FALSE;
+
+ $form['endpoint_object'] = array(
+ '#type' => 'value',
+ '#value' => $endpoint,
+ );
+
+ if (!$server) {
+ $form['message'] = array(
+ '#type' => 'item',
+ '#title' => t('Unknown server @name', array('@name' => $endpoint->server)),
+ '#description' => t('No server matching the one used in the endpoint.'),
+ );
+ }
+ else if (empty($server['settings'])) {
+ $form['message'] = array(
+ '#type' => 'item',
+ '#title' => t('@name has no settings', array('@name' => $endpoint->server)),
+ '#description' => t("The server doesn't have any settings that needs to be configured."),
+ );
+ }
+ else {
+ $definition = $server['settings'];
+
+ $settings = isset($endpoint->server_settings[$endpoint->server]) ? $endpoint->server_settings[$endpoint->server] : array();
+
+ if (!empty($definition['file'])) {
+ call_user_func_array('module_load_include', $definition['file']);
+ }
+
+ $form[$endpoint->server] = array(
+ '#type' => 'fieldset',
+ '#title' => $server['name'],
+ '#tree' => TRUE,
+ );
+ call_user_func_array($definition['form'], array(&$form[$endpoint->server], $endpoint, $settings));
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => 'Save',
+ );
+ }
+
+ return $form;
+}
+
+function services_edit_form_endpoint_server_submit($form, $form_state) {
+ $endpoint = $form_state['values']['endpoint_object'];
+ $servers = services_get_servers();
+ $definition = $servers[$endpoint->server]['settings'];
+
+ $values = $form_state['values'][$endpoint->server];
+
+ // Allow the server to alter the submitted values before they're stored
+ // as settings.
+ if (!empty($definition['submit'])) {
+ if (!empty($definition['file'])) {
+ call_user_func_array('module_load_include', $definition['file']);
+ }
+ $values = call_user_func($definition['submit'], $endpoint, $values);
+ }
+
+ // Store the settings in the endpoint
+ $endpoint->server_settings[$endpoint->server] = $values;
+ services_endpoint_save($endpoint);
+
+ drupal_set_message(t('Your server settings have been saved.'));
+}
/**
* services_edit_endpoint_resources function.
@@ -140,7 +219,7 @@ function services_edit_endpoint_resources($endpoint) {
* @param object $endpoint
* @return Form
*/
-function services_edit_form_endpoint_resources($form, &$form_state) {
+function services_edit_form_endpoint_resources(&$form_state, $endpoint) {
module_load_include('resource_build.inc', 'services');
$form = array();
@@ -148,7 +227,6 @@ function services_edit_form_endpoint_resources($form, &$form_state) {
drupal_add_js('misc/tableselect.js');
drupal_add_js(drupal_get_path('module', 'services') . '/js/services.admin.js');
drupal_add_css(drupal_get_path('module', 'services') . '/css/services.admin.css');
- $endpoint = $form_state;
$form['endpoint_object'] = array(
'#type' => 'value',
'#value' => $endpoint,
@@ -179,7 +257,7 @@ function services_edit_form_endpoint_resources($form, &$form_state) {
'#theme' => 'services_resource_table',
);
- $ignoreArray = array('actions', 'relationships', 'endpoint', 'name', 'file');
+ $ignoreArray = array('actions', 'relationships', 'endpoint', 'name', 'file', 'targeted_actions');
// Generate the list of methods arranged by resource.
foreach ($resources as $resource => $methods) {
$form['resources']['table'][$resource] = array(
@@ -258,7 +336,7 @@ function services_edit_form_endpoint_resources($form, &$form_state) {
* @param array $form_state
* @return void
*/
-function services_edit_form_endpoint_resources_validate($form, $form_state) {
+function services_edit_form_endpoint_resources_validate($form, &$form_state) {
$input = $form_state['values']['endpoint_object'];
// Validate aliases.
@@ -280,7 +358,7 @@ function services_edit_form_endpoint_resources_validate($form, $form_state) {
* @param array $form_state
* @return void
*/
-function services_edit_form_endpoint_resources_submit($form, $form_state) {
+function services_edit_form_endpoint_resources_submit($form, &$form_state) {
$endpoint = $form_state['values']['endpoint_object'];
$existing_resources = _services_build_resources();
@@ -312,4 +390,4 @@ function services_edit_form_endpoint_resources_submit($form, $form_state) {
$endpoint->resources = $final_resource;
services_endpoint_save($endpoint);
drupal_set_message('Resources have been saved');
-}
\ No newline at end of file
+}
diff --git a/plugins/export_ui/services_ctools_export_ui.inc b/plugins/export_ui/services_ctools_export_ui.inc
index cb33c63..d4ec02b 100644
--- a/plugins/export_ui/services_ctools_export_ui.inc
+++ b/plugins/export_ui/services_ctools_export_ui.inc
@@ -17,7 +17,16 @@ $plugin = array(
'load arguments' => array('services_ctools_export_ui'),
'access arguments' => array('administer services'),
'type' => MENU_LOCAL_TASK,
-
+ ),
+ 'server' => array(
+ 'path' => 'list/%ctools_export_ui/server',
+ 'title' => 'Server',
+ 'page callback' => 'ctools_export_ui_switcher_page',
+ 'page arguments' => array('services_ctools_export_ui', 'server', 4),
+ 'load arguments' => array('services_ctools_export_ui'),
+ 'access arguments' => array('administer services'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => -1,
),
'authentication' => array(
'path' => 'list/%ctools_export_ui/authentication',
@@ -34,6 +43,7 @@ $plugin = array(
// Add our custom operations.
'allowed operations' => array(
'resources' => array('title' => t('Edit Resources')),
+ 'server' => array('title' => t('Edit Server')),
'authentication' => array('title' => t('Edit Authentication')),
),
'form' => array(
@@ -71,15 +81,6 @@ function services_ctools_export_ui_form(&$form, &$form_state) {
'#value' => $endpoint,
);
- $form['title'] = array(
- '#type' => 'textfield',
- '#size' => 24,
- '#maxlength' => 255,
- '#default_value' => $endpoint->title,
- '#title' => t('Endpoint title'),
- '#required' => TRUE,
- );
-
$servers = services_get_servers();
$server_opts = array(
'' => t('-- Select a server'),
@@ -138,17 +139,14 @@ function services_ctools_export_ui_form(&$form, &$form_state) {
'#options' => $auth_options,
'#default_value' => $default_values,
'#title' => t('Authentication'),
- '#description' => t('Choose which authentication schemes that should ' .
- 'be used with your endpoint. If no authentication method is selected ' .
- 'the standard Drupal session security is used.'),
+ '#description' => t('Choose which authentication schemes that should be used with your endpoint. If no authentication method is selected all requests will be done by an anonymous user.'),
);
}
else {
$form['authentication'] = array(
'#type' => 'item',
'#title' => t('Authentication'),
- '#description' => t('No authentication modules are installed, standard ' .
- 'Drupal session based security will be used.'),
+ '#description' => t('No authentication modules are installed, all requests will be done by an anonymous user.'),
);
}
@@ -182,10 +180,12 @@ function services_ctools_export_ui_form_validate(&$form, &$form_state) {
* Submit handler for endpoint.
*/
function services_ctools_export_ui_form_submit(&$form, &$form_state) {
+
+ variable_set('services_use_content_permissions', $form_state['values']['services_use_content_permissions']);
+
$endpoint = $form_state['values']['endpoint_object'];
$endpoint->name = $form_state['values']['name'];
- $endpoint->title = $form_state['values']['title'];
$endpoint->server = $form_state['values']['server'];
$endpoint->path = $form_state['values']['path'];
$endpoint->debug = $form_state['values']['debug'];
diff --git a/resources/comment_resource.inc b/resources/comment_resource.inc
index 0270cb2..dc61c2a 100644
--- a/resources/comment_resource.inc
+++ b/resources/comment_resource.inc
@@ -130,7 +130,7 @@ function _comment_resource_definition() {
'name' => 'nid',
'type' => 'int',
'description' => t('The node id to count all comments.'),
- 'source' => 'data',
+ 'source' => array('data' => 'nid'),
'optional' => FALSE,
),
),
@@ -146,15 +146,15 @@ function _comment_resource_definition() {
'name' => 'nid',
'type' => 'int',
'description' => t('The node id to load comments for.'),
- 'source' => 'data',
+ 'source' => array('data' => 'nid'),
'optional' => FALSE,
),
array(
- 'name' => 'since',
- 'type' => 'int',
- 'optional' => TRUE,
- 'description' => t('Timestamp to count from (defaults to time of last user acces to node).'),
- 'source' => 'data',
+ 'name' => 'since',
+ 'type' => 'int',
+ 'optional' => TRUE,
+ 'description' => t('Timestamp to count from (defaults to time of last user acces to node).'),
+ 'source' => array('data' => 'since'),
'optional' => TRUE,
'default value' => 0,
),
@@ -194,7 +194,7 @@ function _comment_resource_index($page, $fields, $parameters) {
if (!user_access('administer comments')) {
$parameters['status'] = 1;
}
- $query = services_resource_build_index_query('comments', 'timestamp DESC', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('comments', 'c.timestamp DESC', $page, $fields, $parameters, 'c', 'cid');
// Put together array of matching nodes to return.
$results = array();
while ($comments = db_fetch_object($query)) {
@@ -214,6 +214,10 @@ function _comment_resource_index($page, $fields, $parameters) {
*/
function _comment_resource_create($comment) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($comment['comment']) && !isset($comment['subject'])) {
+ $comment = $comment['comment'];
+ }
// Setup form_state
$form_state = array();
@@ -265,6 +269,10 @@ function _comment_resource_retrieve($cid) {
*/
function _comment_resource_update($cid, $comment) {
$comment['cid'] = $cid;
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($comment['data']) && !isset($comment['subject'])) {
+ $comment = $comment['data'];
+ }
$old_comment = (array) _comment_load($cid);
if (empty($old_comment)) {
@@ -344,6 +352,11 @@ function _comment_resource_count_new($nid, $since = 0) {
* Access check callback for comment controllers.
*/
function _comment_resource_access($op = 'view', $args = array()) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($args[0]['comment']) || isset($args[0]['data'])) {
+ $args[0] = $args[0]['comment'] ? $args[0]['comment'] : $args[0]['data'];
+ }
+
if ($op == 'view' && !isset($args[0])) {
return user_access('access comments');
}
diff --git a/resources/file_resource.inc b/resources/file_resource.inc
index 0b0a96b..0a0c784 100644
--- a/resources/file_resource.inc
+++ b/resources/file_resource.inc
@@ -130,9 +130,9 @@ function _file_resource_definition() {
* @see _node_resource_index() for more notes
**/
function _file_resource_index($page, $fields, $parameters) {
- services_resource_build_index_query('files', 'timestamp DESC', $page, $fields, $parameters);
+ services_resource_build_index_query('files', 'f.timestamp DESC', $page, $fields, $parameters, 'f', 'fid');
- $query = services_resource_build_index_query('files', 'timestamp', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('files', 'f.timestamp', $page, $fields, $parameters, 'f', 'fid');
// Put together array of matching nodes to return.
$results = array();
while ($comments = db_fetch_object($query)) {
@@ -152,6 +152,11 @@ function _file_resource_index($page, $fields, $parameters) {
* Unique identifier for the file (fid) or errors if there was a problem.
*/
function _file_resource_create($file) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($file['file']) && count($file) == 1) {
+ $file = $file['file'];
+ }
+
global $user;
// If the file data is empty then bail.
@@ -237,7 +242,7 @@ function _file_resource_create($file) {
* @return
* The file
*/
-function _file_resource_retrieve($fid, $file_contents = TRUE) {
+function _file_resource_retrieve($fid, $file_contents) {
if ($file = db_fetch_array(db_query('SELECT * FROM {files} WHERE fid = %d', $fid))) {
if ($file_contents) {
$binaryfile = fopen($file['filepath'], 'rb');
@@ -247,6 +252,7 @@ function _file_resource_retrieve($fid, $file_contents = TRUE) {
$file['file'] = base64_encode(fread($binaryfile, filesize($file['filepath'])));
fclose($binaryfile);
}
+ $file['uri'] = services_resource_uri(array('file', $file['fid']));
return $file;
}
return services_error(t('There is no file with the given ID.'));
@@ -313,6 +319,11 @@ function _file_resource_delete($fid) {
* Access check callback for file controllers.
*/
function _file_resource_access($op = 'view', $args = array()) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($args[0]['file']) && count($args[0]) == 1) {
+ $args[0] = $args[0]['file'];
+ }
+
global $user;
if (user_access('administer files')) {
return TRUE;
diff --git a/resources/node_resource.inc b/resources/node_resource.inc
index d6c5786..6d0ba8f 100644
--- a/resources/node_resource.inc
+++ b/resources/node_resource.inc
@@ -105,28 +105,28 @@ function _node_resource_definition() {
'access arguments' => array('access content'),
),
'relationships' => array(
- 'nodeFiles' => array(
- 'help' => t('This method returns the files on a given node.'),
+ 'files' => array(
'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'help' => t('This method returns files associated with a node.'),
'access callback' => '_node_resource_access',
'access arguments' => array('view'),
'access arguments append' => TRUE,
'callback' => '_node_resource_load_node_files',
'args' => array(
array(
- 'name' => 'nid',
- 'type' => 'int',
- 'description' => t('The node id to load files for.'),
- 'source' => 'data',
- 'optional' => FALSE,
+ 'name' => 'nid',
+ 'optional' => FALSE,
+ 'source' => array('path' => 0),
+ 'type' => 'int',
+ 'description' => 'The nid of the node whose files we are getting',
),
array(
- 'name' => 'file_contents',
- 'type' => 'int',
+ 'name' => 'file_contents',
+ 'type' => 'int',
'description' => t('To return file contents or not.'),
- 'source' => 'data',
- 'optional' => FALSE,
- 'default value' => TRUE,
+ 'source' => array('path' => 2),
+ 'optional' => TRUE,
+ 'default value' => false,
),
),
),
@@ -245,6 +245,11 @@ function _node_resource_retrieve($nid) {
* @see drupal_execute()
*/
function _node_resource_create($node) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($node['node'])) {
+ $node = $node['node'];
+ }
+
if (!isset($node['type'])) {
return services_error('Missing node type', 406);
}
@@ -299,6 +304,11 @@ function _node_resource_create($node) {
* @see drupal_execute()
*/
function _node_resource_update($nid, $node) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($node['node'])) {
+ $node = $node['node'];
+ }
+
$node['nid'] = $nid;
$old_node = node_load($nid);
@@ -374,7 +384,7 @@ function _node_resource_index($page, $fields, $parameters) {
if (!user_access('administer nodes')) {
$parameters['status'] = 1;
}
- $query = services_resource_build_index_query('node', 'sticky DESC, created DESC', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('node', 'n.sticky DESC, n.created DESC', $page, $fields, $parameters, 'n', 'nid');
// Put together array of matching nodes to return.
$results = array();
while ($node = db_fetch_object($query)) {
@@ -394,7 +404,7 @@ function _node_resource_index($page, $fields, $parameters) {
* @return
* Array. A list of all files from the given node
*/
-function _node_resource_load_node_files($nid, $include_file_contents = TRUE) {
+function _node_resource_load_node_files($nid, $include_file_contents) {
module_load_include('inc', 'services', 'resources/file_resource');
$node = node_load($nid);
if (!isset($node->files)) {
@@ -407,21 +417,7 @@ function _node_resource_load_node_files($nid, $include_file_contents = TRUE) {
if (!$file->list) {
continue;
}
- $return[$file->fid] = array(
- 'filename' => $file->filename,
- 'uid' => $file->uid,
- 'filemime' => $file->filemime,
- 'filesize' => $file->filesize,
- 'status' => $file->status,
- 'timestamp' => $file->timestamp
- );
- // If to add content of the file.
- if ($file_include_contents) {
- $filepath = file_create_path($file->filepath);
- $binaryfile = fopen($filepath, 'rb');
- $return[$file->fid]['file'] = base64_encode(fread($binaryfile, filesize($filepath)));
- fclose($binaryfile);
- }
+ $return[$file->fid] = _file_resource_retrieve($file->fid, $include_file_contents);
}
return $return;
@@ -439,6 +435,11 @@ function _node_resource_load_node_files($nid, $include_file_contents = TRUE) {
* @see node_access()
*/
function _node_resource_access($op = 'view', $args = array()) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($args[0]['node'])) {
+ $args[0] = $args[0]['node'];
+ }
+
// Make sure we have an object or this all fails, some servers can
// mess up the types.
if (is_array($args[0])) {
diff --git a/resources/system_resource.inc b/resources/system_resource.inc
index 6d626f5..8b63362 100644
--- a/resources/system_resource.inc
+++ b/resources/system_resource.inc
@@ -24,14 +24,14 @@ function _system_resource_definition() {
array(
'name' => 'name',
'optional' => TRUE,
- 'source' => 'data',
+ 'source' => array('data' => 'name'),
'description' => t('The name of the variable to return.'),
'type' => 'string',
),
array(
'name' => 'default',
'optional' => FALSE,
- 'source' => 'data',
+ 'source' => array('data' => 'default'),
'description' => t('The default value to use if this variable has never been set.'),
'type' => 'string',
),
@@ -47,14 +47,14 @@ function _system_resource_definition() {
array(
'name' => 'name',
'optional' => FALSE,
- 'source' => 'data',
+ 'source' => array('data' => 'name'),
'description' => t('The name of the variable to set.'),
'type' => 'string',
),
array(
'name' => 'value',
'optional' => FALSE,
- 'source' => 'data',
+ 'source' => array('data' => 'value'),
'description' => t('The value to set.'),
'type' => 'string',
),
@@ -70,7 +70,7 @@ function _system_resource_definition() {
array(
'name' => 'name',
'optional' => FALSE,
- 'source' => 'data',
+ 'source' => array('data' => 'name'),
'description' => t('The name of the variable to delete.'),
'type' => 'string',
),
diff --git a/resources/taxonomy_resource.inc b/resources/taxonomy_resource.inc
index 00b93e0..14c1780 100644
--- a/resources/taxonomy_resource.inc
+++ b/resources/taxonomy_resource.inc
@@ -124,14 +124,14 @@ function _taxonomy_resource_definition() {
'name' => 'tids',
'type' => 'string',
'description' => t('The vocabulary ids to retrieve, separated by comma.'),
- 'source' => 'data',
+ 'source' => array('data' => 'tids'),
'optional' => FALSE,
),
array(
'name' => 'fields',
'type' => 'string',
'description' => t('The fields to retrieve, separated by comma.'),
- 'source' => 'data',
+ 'source' => array('data' => 'fields'),
'optional' => TRUE,
'default value' => array(),
),
@@ -139,7 +139,7 @@ function _taxonomy_resource_definition() {
'name' => 'operator',
'type' => 'string',
'description' => t('How to interpret multiple IDs in the array. Can be "or" or "and".'),
- 'source' => 'data',
+ 'source' => array('data' => 'operator'),
'optional' => TRUE,
'default value' => 'or',
),
@@ -147,7 +147,7 @@ function _taxonomy_resource_definition() {
'name' => 'depth',
'type' => 'int',
'description' => t('How many levels deep to traverse the taxonomy tree. Can be a nonnegative integer or "all".'),
- 'source' => 'data',
+ 'source' => array('data' => 'depth'),
'optional' => TRUE,
'default value' => 0,
),
@@ -155,7 +155,7 @@ function _taxonomy_resource_definition() {
'name' => 'pager',
'type' => 'int',
'description' => t('Whether the nodes are to be used with a pager (the case on most Drupal pages) or not (in an XML feed, for example).'),
- 'source' => 'data',
+ 'source' => array('data' => 'pager'),
'optional' => TRUE,
'default value' => TRUE,
),
@@ -163,7 +163,7 @@ function _taxonomy_resource_definition() {
'name' => 'order',
'type' => 'string',
'description' => t('The order clause for the query that retrieve the nodes.'),
- 'source' => 'data',
+ 'source' => array('data' => 'order'),
'optional' => TRUE,
'default value' => 'n.sticky DESC, n.created DESC',
),
@@ -286,24 +286,24 @@ function _taxonomy_resource_definition() {
'name' => 'vid',
'type' => 'int',
'description' => t('The vocabulary id to retrieve.'),
- 'source' => 'data',
+ 'source' => array('data' => 'vid'),
'optional' => FALSE,
),
array(
- 'name' => 'parent',
- 'type' => 'int',
- 'description' => t('The term ID under which to generate the tree. If 0, generate the tree for the entire vocabulary.'),
- 'source' => 'data',
- 'default value' => 0,
- 'optional' => TRUE,
+ 'name' => 'parent',
+ 'type' => 'int',
+ 'description' => t('The term ID under which to generate the tree. If 0, generate the tree for the entire vocabulary.'),
+ 'source' => array('data' => 'parent'),
+ 'default value' => 0,
+ 'optional' => TRUE,
),
array(
- 'name' => 'maxdepth',
- 'type' => 'int',
- 'description' => t('The number of levels of the tree to return. Leave NULL to return all levels.'),
- 'source' => 'data',
- 'optional' => TRUE,
- 'default value' => NULL,
+ 'name' => 'maxdepth',
+ 'type' => 'int',
+ 'description' => t('The number of levels of the tree to return. Leave NULL to return all levels.'),
+ 'source' => array('data' => 'maxdepth'),
+ 'default value' => NULL,
+ 'optional' => TRUE,
),
),
),
@@ -334,7 +334,7 @@ function _taxonomy_resource_definition() {
* @see _node_resource_index() for more notes
**/
function _taxonomy_term_resource_index($page, $fields, $parameters) {
- $query = services_resource_build_index_query('term_data', 'vid DESC, weight DESC, name DESC', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('term_data', 't.vid DESC, t.weight DESC, t.name DESC', $page, $fields, $parameters, 't', 'tid');
$results = array();
while ($taxonomy = db_fetch_object($query)) {
@@ -369,7 +369,7 @@ function _taxonomy_term_resource_index($page, $fields, $parameters) {
* @see _node_resource_index() for more notes
**/
function _taxonomy_vocabulary_resource_index($page, $fields, $parameters) {
- $query = services_resource_build_index_query('vocabulary', 'weight DESC, name DESC', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('vocabulary', 'v.weight DESC, v.name DESC', $page, $fields, $parameters, 'v', 'vid');
$results = array();
while ($taxonomy = db_fetch_object($query)) {
@@ -403,6 +403,11 @@ function _taxonomy_term_resource_retrieve($tid) {
* @see taxonomy_save_term()
*/
function _taxonomy_term_resource_create($term) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($term['term'])) {
+ $term = $term['term'];
+ }
+
return taxonomy_save_term($term);
}
@@ -419,6 +424,11 @@ function _taxonomy_term_resource_create($term) {
* @see taxonomy_save_term()
*/
function _taxonomy_term_resource_update($tid, $term) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($term['term'])) {
+ $term = $term['term'];
+ }
+
$term['tid'] = $tid;
return _taxonomy_term_resource_create($term);
}
@@ -482,7 +492,12 @@ function _taxonomy_vocabulary_resource_retrieve($vid) {
* @see taxonomy_save_vocabulary()
*/
function _taxonomy_vocabulary_resource_create($vocabulary) {
- return taxonomy_save_vocabulary($vocabulary);
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($vocabulary['vocabulary'])) {
+ $vocabulary = $vocabulary['vocabulary'];
+ }
+ taxonomy_save_vocabulary($vocabulary);
+ return $vocabulary;
}
/**
@@ -498,6 +513,11 @@ function _taxonomy_vocabulary_resource_create($vocabulary) {
* @see taxonomy_save_vocabulary()
*/
function _taxonomy_vocabulary_resource_update($vid, $vocabulary) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($vocabulary['vocabulary'])) {
+ $vocabulary = $vocabulary['vocabulary'];
+ }
+
$vocabulary['vid'] = $vid;
return _taxonomy_vocabulary_resource_create($vocabulary);
}
@@ -559,7 +579,7 @@ function taxonomy_service_select_nodes($tids, $fields, $operator, $depth, $pager
}
function _taxonomy_resource_access($op = 'view', $args = array()) {
- if (user_access('administer taxonomy')) {
+ if (user_access('administer taxonomy') || user_access('get taxonomy tree')) {
return TRUE;
}
// TODO - check perms of user to return ability to interact with terms / vocabulary
diff --git a/resources/user_resource.inc b/resources/user_resource.inc
index cd46157..5a497fc 100644
--- a/resources/user_resource.inc
+++ b/resources/user_resource.inc
@@ -121,14 +121,14 @@ function _user_resource_definition() {
'name' => 'username',
'type' => 'string',
'description' => 'A valid username',
- 'source' => 'data',
+ 'source' => array('data' => 'username'),
'optional' => FALSE,
),
array(
'name' => 'password',
'type' => 'string',
'description' => 'A valid password',
- 'source' => 'data',
+ 'source' => array('data' => 'password'),
'optional' => FALSE,
),
),
@@ -211,6 +211,11 @@ function _user_resource_retrieve($uid) {
* The user object of the newly created user.
*/
function _user_resource_create($account) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($account['account'])) {
+ $account = $account['account'];
+ }
+
// Load the required includes for saving profile information
// with drupal_execute().
module_load_include('inc', 'user', 'user.pages');
@@ -254,7 +259,13 @@ function _user_resource_create($account) {
* The modified user object.
*/
function _user_resource_update($uid, $account) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($account['data'])) {
+ $account = $account['data'];
+ }
+
$account['uid'] = $uid;
+ $user = user_load($uid);
// Load the required includes for saving profile information
// with drupal_execute().
@@ -287,8 +298,14 @@ function _user_resource_update($uid, $account) {
$form_state['values']['op'] = 'Save';
$form_state['values']['_category'] = $category;
$form_state['values']['_account'] = (object)$account;
+ if (isset($account['pass'])) {
+ $form_state['values']['pass'] = array(
+ 'pass1' => $account['pass'],
+ 'pass2' => $account['pass'],
+ );
+ }
- $ret = drupal_execute('user_profile_form', $form_state, (object)$account, $category);
+ $ret = drupal_execute('user_profile_form', $form_state, $user, $category);
// Error if needed.
if ($errors = form_get_errors()) {
@@ -370,7 +387,8 @@ function _user_resource_logout() {
// Destroy the current session:
session_destroy();
- module_invoke_all('user', 'logout', NULL, $user);
+ $null = NULL; // Only variables can be passed by reference workaround
+ user_module_invoke('logout', $null, $user );
// Load the anonymous user
$user = drupal_anonymous_user();
@@ -404,7 +422,7 @@ function _user_resource_index($page, $fields, $parameters) {
if (!user_access('administer users')) {
$parameters['active'] = 1;
}
- $query = services_resource_build_index_query('users', 'created DESC', $page, $fields, $parameters);
+ $query = services_resource_build_index_query('users', 'u.created DESC', $page, $fields, $parameters, 'u', 'uid');
$results = array();
while ($user = db_fetch_object($query)) {
@@ -417,6 +435,11 @@ function _user_resource_index($page, $fields, $parameters) {
* Access check callback for user resource.
*/
function _user_resource_access($op = 'view', $args = array()) {
+ // Adds backwards compatability with regression fixed in #1083242
+ if (isset($args[0]['account']) || isset($args[0]['data'])) {
+ $args[0] = $args[0]['account'] ? $args[0]['account'] : $args[0]['data'];
+ }
+
global $user;
switch ($op) {
case 'view':
diff --git a/servers/rest_server/includes/RESTServer.inc b/servers/rest_server/includes/RESTServer.inc
index f1ab017..b67bf34 100755
--- a/servers/rest_server/includes/RESTServer.inc
+++ b/servers/rest_server/includes/RESTServer.inc
@@ -53,6 +53,15 @@ class RESTServer {
}
$endpoint = services_get_server_info('endpoint', '');
+
+ $endpoint_definition = services_endpoint_load($endpoint);
+
+ // Get the server settings from the endpoint.
+ $this->settings = !empty($endpoint_definition->server_settings['rest_server']) ? $endpoint_definition->server_settings['rest_server'] : array();
+ // Normalize the settings so that we get the expected structure
+ // and sensible defaults.
+ $this->settings = rest_server_setup_settings($this->settings);
+
$resources = services_get_resources($endpoint);
$controller = FALSE;
if (!empty($resource_name) && isset($resources[$resource_name])) {
@@ -83,7 +92,6 @@ class RESTServer {
// Negotiate response format based on accept-headers if we
// don't have a response format
if (empty($response_format)) {
- module_load_include('php', 'rest_server', 'lib/mimeparse');
$mime_candidates = array();
$mime_map = array();
@@ -99,7 +107,7 @@ class RESTServer {
// Get the best matching format, default to json
if (isset($_SERVER['HTTP_ACCEPT'])) {
- $mime = new Mimeparse();
+ $mime = $this->mimeParse();
$mime_type = $mime->best_match($mime_candidates, $_SERVER['HTTP_ACCEPT']);
}
@@ -152,7 +160,7 @@ class RESTServer {
$result = services_controller_execute($controller, $arguments);
} catch (ServicesException $e) {
$errors = $this->handleException($e);
- drupal_alter('rest_server_exectue_errors', $errors, $controller, $arguments);
+ drupal_alter('rest_server_execute_errors', $errors, $controller, $arguments);
$result = $errors;
}
$formatter = $formats[$response_format];
@@ -218,16 +226,15 @@ class RESTServer {
}
}
else {
- if (isset($sources[$info['source']][$info['name']])) {
- $arguments[$i] = $sources[$info['source']][$info['name']];
- }
+ if (isset($sources[$info['source']])) {
+ $arguments[$i] = $sources[$info['source']];
+ }
}
// Convert to array if argument expected to be array.
if ($info['type'] == 'array' && isset($arguments[$i])) {
$arguments[$i] = (array)$arguments[$i];
}
}
-
// When argument isn't set, insert default value if provided or
// throw a exception if the argument isn't optional.
if (!isset($arguments[$i])) {
@@ -249,15 +256,11 @@ class RESTServer {
}
private function parseRequest($method, $controller) {
- if (($method == 'POST' || $method == 'PUT') && isset($_SERVER['CONTENT_TYPE'])) {
- $type = self::parseContentHeader($_SERVER['CONTENT_TYPE']);
- }
+
switch ($method) {
case 'POST':
- if (isset($type['value']) && $type['value'] == 'application/x-www-form-urlencoded') {
- return $_POST;
- }
case 'PUT':
+ $type = self::parseContentHeader($_SERVER['CONTENT_TYPE']);
// Get the mime type for the request, default to form-urlencoded
if (isset($type['value'])) {
$mime = $type['value'];
@@ -267,7 +270,7 @@ class RESTServer {
}
// Get the parser for the mime type
- $parser = $this->requestParsers($mime, $controller);
+ $parser = $this->requestParser($mime, $controller);
if (!$parser) {
throw new ServicesException(t('Unsupported request content type !mime', array(
'!mime' => $mime,
@@ -400,32 +403,34 @@ class RESTServer {
return $view->render();
}
- private function requestParsers($mime=NULL, $controller=NULL) {
- static $parsers;
-
+ private function requestParser($mime = NULL, $controller = NULL) {
+ // Check if the controller has declared support for parsing the mime type.
if ($mime && $controller && !empty($controller['rest request parsers'])) {
- $parser = $this->matchParser($mime, $controller['rest request parsers']);
+ $parser = $this->matchParser($mime, $controller['rest request parsers'], TRUE);
if ($parser) {
return $parser;
}
}
- if (!$parsers) {
- $parsers = array(
- 'application/x-www-form-urlencoded' => 'RESTServer::parseURLEncoded',
- 'application/x-yaml' => 'RESTServer::parseYAML',
- 'application/json' => 'RESTServer::parseJSON',
- 'application/vnd.php.serialized' => 'RESTServer::parsePHP',
- );
- drupal_alter('rest_server_request_parsers', $parsers);
- }
if ($mime) {
+ $parsers = rest_server_request_parsers();
+
+ // Remove parsers that have been disabled for this endpoint.
+ foreach (array_keys($parsers) as $key) {
+ if (!$this->settings['parsers'][$key]) {
+ unset($parsers[$key]);
+ }
+ }
return $this->matchParser($mime, $parsers);
}
- return $parsers;
+ return FALSE;
}
-
+ /**
+ * Create a instance of the Mimeparse utility class.
+ *
+ * @return Mimeparse
+ */
private function mimeParse() {
static $mimeparse;
if (!$mimeparse) {
@@ -435,12 +440,10 @@ class RESTServer {
return $mimeparse;
}
- private function matchParser($mime, $parsers) {
+ private function matchParser($mime, $parsers, $allow_all_parsers = FALSE) {
$mimeparse = $this->mimeParse();
$mime_type = $mimeparse->best_match(array_keys($parsers), $mime);
- if ($mime_type) {
- return $parsers[$mime_type];
- }
+ return ($mime_type) ? $parsers[$mime_type] : FALSE;
}
public static function parseURLEncoded($handle) {
@@ -462,52 +465,18 @@ class RESTServer {
}
private function responseFormatters($format=NULL) {
- static $formatters;
-
- if (!$formatters) {
- $formatters = array(
- 'xml' => array(
- 'mime types' => array('application/xml', 'text/xml'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'xml'),
- ),
- 'json' => array(
- 'mime types' => array('application/json'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'json'),
- ),
- 'jsonp' => array(
- 'mime types' => array('text/javascript', 'application/javascript'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'jsonp'),
- ),
- 'php' => array(
- 'mime types' => array('application/vnd.php.serialized'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'php'),
- ),
- 'yaml' => array(
- 'mime types' => array('text/plain', 'application/x-yaml', 'text/yaml'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'yaml'),
- ),
- 'bencode' => array(
- 'mime types' => array('application/x-bencode'),
- 'view' => 'RESTServerViewBuiltIn',
- 'view arguments' => array('format' => 'bencode'),
- ),
- 'rss' => array(
- 'model' => 'ResourceFeedModel',
- 'mime types' => array('text/xml'),
- 'view' => 'RssFormatView',
- ),
- );
- drupal_alter('rest_server_response_formatters', $formatters);
- }
+ $formatters = rest_server_response_formatters();
+ // Remove formatters that have been disabled for this endpoint.
+ foreach (array_keys($formatters) as $key) {
+ if (!$this->settings['formatters'][$key]) {
+ unset($formatters[$key]);
+ }
+ }
if ($format) {
return isset($formatters[$format]) ? $formatters[$format] : FALSE;
}
+
return $formatters;
}
@@ -589,7 +558,7 @@ class RESTServer {
}
// Detect action requests targeted at specific resources
elseif ($pc >= 2 && $method == 'POST') {
- $action = $resource['targeted actions'][$path[1]];
+ $action = $resource['targeted_actions'][$path[1]];
return $action;
}
}
diff --git a/servers/rest_server/rest_server.api.php b/servers/rest_server/rest_server.api.php
index 7e0217f..23b1d26 100644
--- a/servers/rest_server/rest_server.api.php
+++ b/servers/rest_server/rest_server.api.php
@@ -11,22 +11,51 @@
*/
/**
- * ...
+ * Triggered when the REST server request a list of available request parsers.
*
+ * @param array $parsers
+ * An associative array of parser callbacks keyed by mime-type.
+ * @return void
*/
-function hook_rest_server_request_parsers_alter() {
- return array(
- 'name' => 'REST',
- );
+function hook_rest_server_request_parsers_alter(&$parsers) {
+ $parsers['application/json'] = 'RESTServer::parseJSON';
+ unset($parsers['application/x-www-form-urlencoded']);
}
/**
- * ...
+ * Triggered when the REST server request a list of supported response formats.
*
+ * @param array $formatters
+ * An associative array of formatter info arrays keyed by type extension. The
+ * formatter info specifies an array of 'mime types' that corresponds to the
+ * output format; a 'view' class that is a subclass of RESTServerView; and
+ * 'view arguments' that should be passed to the view when it is created;
+ * a 'model' can also be specified which the controller then must declare
+ * support for to be able to serve data in that format.
+ * @return void
*/
-function hook_rest_server_response_formatters_alter() {
- return array(
- 'name' => 'REST',
+function hook_rest_server_response_formatters_alter(&$formatters) {
+ /*
+ * Sample modifications of the formatters array. Both yaml and
+ * rss are formats that already are supported, so the changes are
+ * nonsensical but illustrates the proper use of this hook.
+ */
+
+ // Add a Yaml response format.
+ $formatters['yaml'] = array(
+ 'mime types' => array('text/plain', 'application/x-yaml', 'text/yaml'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'yaml'),
);
+
+ // Add a Rss response format.
+ $formatters['rss'] = array(
+ 'model' => 'ResourceFeedModel',
+ 'mime types' => array('text/xml'),
+ 'view' => 'RssFormatView',
+ );
+
+ // Remove the jsonp response format.
+ unset($formatters['jsonp']);
}
diff --git a/servers/rest_server/rest_server.inc b/servers/rest_server/rest_server.inc
index 462a8ac..563f06f 100644
--- a/servers/rest_server/rest_server.inc
+++ b/servers/rest_server/rest_server.inc
@@ -2,9 +2,93 @@
/**
* @file
- * Autoload classes.
+ * Autoload classes and server settings.
*/
+/**
+ * REST server settings form. Generates the form fragment for configuring the REST server
+ * for an endpoint.
+ *
+ * @param array $form
+ * The form fragment from services that we should add our fields to.
+ * @param object $endpoint
+ * The endpoint that we're configuring the REST server for.
+ * @param array $settings
+ * The current settings.
+ * @return void
+ */
+function _rest_server_settings(&$form, $endpoint, $settings) {
+ $settings = rest_server_setup_settings($settings);
+
+ $form['formatters'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Response formatters'),
+ '#required' => TRUE,
+ '#description' => t('Select the response formats you want to enable for the rest server.'),
+ ) + _rest_server_settings_checkboxes_attributes($settings['formatters']);
+
+ $form['parsers'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Request parsing'),
+ '#required' => TRUE,
+ '#description' => t('Select the request parser types you want to enable for the rest server.'),
+ ) + _rest_server_settings_checkboxes_attributes($settings['parsers']);
+}
+
+/**
+ * Utility function that creates attributes for a checkboxes-type form
+ * element from a rest server settings array.
+ *
+ * @param array $settings
+ * @return array
+ */
+function _rest_server_settings_checkboxes_attributes($settings) {
+ $keys = array_keys($settings);
+ $options = array_combine($keys, $keys);
+ $default = array();
+ foreach ($settings as $key => $enabled) {
+ if ($enabled) {
+ $default[] = $key;
+ }
+ }
+ return array(
+ '#options' => $options,
+ '#default_value' => $default,
+ );
+}
+
+/**
+ * Submit handler for the services REST server settings form.
+ *
+ * @param object $endpoint
+ * The endpoint that's being configured.
+ * @param array $values
+ * The partial form-state from services.
+ * @return array
+ * The settings for the REST server in this endpoint.
+ */
+function _rest_server_settings_submit($endpoint, $values) {
+ $values['formatters'] = array_map('_rest_server_settings_not_zero', $values['formatters']);
+ $values['parsers'] = array_map('_rest_server_settings_not_zero', $values['parsers']);
+ return $values;
+}
+
+/**
+ * Utility function intended for use with array_map to change everything that
+ * isn't === 0 into TRUE.
+ *
+ * @param string $value
+ * The value to map.
+ * @return bool
+ * FALSE if the $value is === 0 otherwise TRUE is returned.
+ */
+function _rest_server_settings_not_zero($value) {
+ return $value !== 0;
+}
+
+/**
+ * Actual implementation of hook_autoload_info().
+ */
function _rest_server_autoload_info() {
return array(
'RESTServer' => array(
diff --git a/servers/rest_server/rest_server.module b/servers/rest_server/rest_server.module
index d7e4669..127e1f0 100755
--- a/servers/rest_server/rest_server.module
+++ b/servers/rest_server/rest_server.module
@@ -4,6 +4,11 @@ function rest_server_server_info() {
return array(
'name' => 'REST',
'path' => 'rest',
+ 'settings' => array(
+ 'file' => array('inc', 'rest_server'),
+ 'form' => '_rest_server_settings',
+ 'submit' => '_rest_server_settings_submit',
+ ),
);
}
@@ -43,7 +48,135 @@ function rest_server_server() {
}
/**
- * Implementation of hook_services_resources_alter().
+ * Builds a list of request parsers that are available to the RESTServer.
+ *
+ * @return array
+ * An associative array of parser callbacks keyed by mime-type.
+ */
+function rest_server_request_parsers() {
+ static $parsers = NULL;
+ if (!$parsers) {
+ $parsers = array(
+ 'application/x-www-form-urlencoded' => 'RESTServer::parseURLEncoded',
+ 'application/x-yaml' => 'RESTServer::parseYAML',
+ 'application/json' => 'RESTServer::parseJSON',
+ 'application/vnd.php.serialized' => 'RESTServer::parsePHP',
+ );
+ drupal_alter('rest_server_request_parsers', $parsers);
+ }
+ return $parsers;
+}
+
+/**
+ * Builds a list of response formatters that are available to the RESTServer.
+ *
+ * @return array
+ * An associative array of formatter info arrays keyed by type extension. The
+ * formatter info specifies an array of 'mime types' that corresponds to the
+ * output format; a 'view' class that is a subclass of RESTServerView; and
+ * 'view arguments' that should be passed to the view when it is created;
+ * a 'model' can also be specified which the controller then must declare
+ * support for to be able to serve data in that format.
+ */
+function rest_server_response_formatters() {
+ static $formatters = NULL;
+ if (!$formatters) {
+ $formatters = array(
+ 'xml' => array(
+ 'mime types' => array('application/xml', 'text/xml'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'xml'),
+ ),
+ 'json' => array(
+ 'mime types' => array('application/json'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'json'),
+ ),
+ 'jsonp' => array(
+ 'mime types' => array('text/javascript', 'application/javascript'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'jsonp'),
+ ),
+ 'php' => array(
+ 'mime types' => array('application/vnd.php.serialized'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'php'),
+ ),
+ 'yaml' => array(
+ 'mime types' => array('text/plain', 'application/x-yaml', 'text/yaml'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'yaml'),
+ ),
+ 'bencode' => array(
+ 'mime types' => array('application/x-bencode'),
+ 'view' => 'RESTServerViewBuiltIn',
+ 'view arguments' => array('format' => 'bencode'),
+ ),
+ 'rss' => array(
+ 'model' => 'ResourceFeedModel',
+ 'mime types' => array('text/xml'),
+ 'view' => 'RssFormatView',
+ ),
+ );
+ drupal_alter('rest_server_response_formatters', $formatters);
+ }
+ return $formatters;
+}
+
+/**
+ * Set up settings for a rest server endpoint, fills the settings
+ * array with defaults. This is done to ensure that the default state
+ * is consistent between what's shown by default in the settings form
+ * and used by default by the REST server if it hasn't been configured.
+ *
+ * @param array $settings
+ * @return array
+ * The standardized settings array.
+ */
+function rest_server_setup_settings($settings = array()) {
+ // Apply defaults
+ $settings = $settings + array(
+ 'formatters' => array('jsonp' => FALSE),
+ 'parsers' => array('application/x-www-form-urlencoded' => FALSE),
+ );
+
+ // Get all available parsers and formatters.
+ $parsers = rest_server_request_parsers();
+ $formatters = rest_server_response_formatters();
+
+ _rest_server_add_default_and_remove_unknown($settings['parsers'], array_keys($parsers), TRUE);
+ _rest_server_add_default_and_remove_unknown($settings['formatters'], array_keys($formatters), TRUE);
+
+ return $settings;
+}
+
+/**
+ * Utility function set set up an array with default values for a set
+ * of keys and remove all entries that does not match a key in the set.
+ *
+ * @param array $array
+ * The array to modify.
+ * @param array $keys
+ * An array of keys.
+ * @param mixed $default
+ * A default value.
+ * @return void
+ */
+function _rest_server_add_default_and_remove_unknown(&$array, $keys, $default) {
+ foreach ($keys as $k) {
+ if (!isset($array[$k])) {
+ $array[$k] = TRUE;
+ }
+ }
+ foreach (array_keys($array) as $key) {
+ if (!in_array($key, $keys)) {
+ unset($array[$key]);
+ }
+ }
+}
+
+/**
+ * Implements hook_services_resources_alter().
*/
function rest_server_services_resources_alter($resources, $endpoint) {
// Set the default models for the retrieve and index controllers in the node
diff --git a/services.install b/services.install
index 31ccc19..447c6ca 100644
--- a/services.install
+++ b/services.install
@@ -26,12 +26,6 @@ function services_schema() {
'length' => 255,
'not null' => TRUE,
),
- 'title' => array(
- 'description' => 'The title of the endpoint.',
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- ),
'server' => array(
'description' => 'The name of the server used in this endpoint.',
'type' => 'varchar',
@@ -52,6 +46,13 @@ function services_schema() {
'serialize' => TRUE,
'object default' => array(),
),
+ 'server_settings' => array(
+ 'description' => 'The server settings for the endpoint.',
+ 'type' => 'blob',
+ 'size' => 'big',
+ 'not null' => TRUE,
+ 'serialize' => TRUE
+ ),
'resources' => array(
'description' => 'Information about the resources exposed in this endpoint.',
'type' => 'text',
@@ -87,7 +88,37 @@ function services_schema() {
return $schema;
}
+ /**
+ * Implements hook_requirements().
+ */
+function services_requirements($phase) {
+ $requirements = array();
+ $t = get_t();
+ // Warn users of the possible threat.
+ if ($phase == 'runtime') {
+ //Pull endpoints that do not have services authentication enabled
+ $result = db_query('SELECT * FROM {services_endpoint} AS se WHERE se.authentication NOT LIKE "%s"', '%services%');
+ $items = array();
+ $has_endpoint = FALSE;
+ while ($endpoint = db_fetch_object($result)) {
+ $has_endpoint = TRUE;
+ $items[] = l($endpoint->name, 'admin/build/services/list/'. $endpoint->name);
+ }
+ // theme the endpoints list
+ $endpoints = theme('item_list', array('items' => $items));
+ // Only display the list if we have at least one endpoint without services authentication.
+ if ($has_endpoint) {
+ $requirements['services'] = array(
+ 'description' => $t('Services authentication mechanismhas not been enabled for the following endpoints. Requests to these endpoints will always be anonymous.'),
+ 'severity' => REQUIREMENT_ERROR,
+ 'value' => $endpoints,
+ 'title' => 'Services Authentication Mechanism',
+ );
+ }
+ }
+ return $requirements;
+}
/**
* Implementation of hook_install().
*/
@@ -266,24 +297,27 @@ function services_update_6302() {
}
/**
- * Implements hook_requirements().
- *
- * Check version of ctools.
+ * Update 6303 adds the possibility to configure server settings on a per-endpoint basis.
+ * and sets upgrades all new servers to have at least services session enabled.
*/
-function services_requirements($phase) {
- $t = get_t();
- $requirements = array();
- $ctools_info = db_fetch_array(db_query('SELECT info FROM {system} WHERE name = "%s"', 'ctools'));
- $ctools_info = unserialize($ctools_info['info']);
- // Check whether version of ctools is minimum alpha3
- // as we need patch applied from http://drupal.org/node/933946
- if ($ctools_info['datestamp'] < 1299715446) {
- $requirements['ctools'] = array(
- 'title' => 'CTools',
- 'value' => $ctools_info['version'],
- 'severity' => REQUIREMENT_ERROR,
- 'description' => $t('Please update CTools module to latest stable version (minimum 6.x-dev March 09).'),
- );
- }
- return $requirements;
+function services_update_6303() {
+ $ret = array();
+ // Add the new server settings field.
+ $new_field = array(
+ 'description' => 'The server settings for the endpoint.',
+ 'type' => 'blob',
+ 'size' => 'big',
+ 'not null' => TRUE,
+ 'serialize' => TRUE
+ );
+ db_add_field($ret, 'services_endpoint', 'server_settings', $new_field);
+ return $ret;
+}
+/**
+ * Update 6304 removes title functionality as it is no longer used.
+ */
+function services_update_6304() {
+ $ret = array();
+ db_drop_field($ret, 'services_endpoint', 'title');
+ return $ret;
}
\ No newline at end of file
diff --git a/services.module b/services.module
index 46e4ead..bdb1281 100644
--- a/services.module
+++ b/services.module
@@ -35,6 +35,7 @@ function services_help($path, $arg) {
function services_perm() {
return array(
'administer services',
+ 'get taxonomy tree',
// File resource permissions
'get any binary files',
'get own binary files',
@@ -301,6 +302,27 @@ function services_services_resources() {
return array_merge(_services_core_resources(), _services_legacy_services_as_resources());
}
+ /**
+ * Implementation of hook_services_authentication().
+ */
+function services_services_authentication_info() {
+ return array(
+ 'title' => t('Session authentication'),
+ 'description' => t("Uses Drupal's built in sessions to authenticate."),
+ 'authenticate_call' => '_services_sessions_authenticate_call',
+ );
+}
+
+/**
+ * Authenticates a call using Drupal's built in sessions
+ *
+ * @return void
+ */
+function _services_sessions_authenticate_call() {
+ global $user;
+ $user = services_get_server_info('original_user');
+}
+
/**
* Returns all the controller names for a endpoint.
*
@@ -405,7 +427,7 @@ function services_resources_as_procedures($resource) {
*
* @param $resource
* The resource being converted (node, user, etc.)
- * @param $name
+ * @param $name
* The method name (retrieve, create, etc.)
* @param $controller
* Associative array defining the method's properties and callbacks.
@@ -432,9 +454,18 @@ function _services_resource_controller_as_procedure($resource, $name, $controlle
* @param $parameter
* Array parameters to add to the index query.
*/
-function services_resource_build_index_query($schema, $order, $page, $fields, $parameters = array()) {
+function services_resource_build_index_query($schema, $order, $page, $fields, $parameters = array(), $primary_table, $primary_field) {
$where = array();
$fields = db_escape_string($fields);
+
+ // need to append table prefix
+ if ($fields_array = explode(',', $fields)) {
+ foreach ($fields_array as &$field) {
+ $field = $primary_table . '.' . trim($field);
+ }
+ $fields = implode(',', $fields_array);
+ }
+
$schema = db_escape_string($schema);
$table = $schema;
$schema = drupal_get_schema($schema);
@@ -442,7 +473,7 @@ function services_resource_build_index_query($schema, $order, $page, $fields, $p
// db_query().
if(is_array($parameters)) {
foreach ($parameters as $field => $value) {
- $where[] = $field . ' = ' . db_type_placeholder($schema['fields'][$field]['type']);
+ $where[] = $primary_table . '.' . $field . ' = ' . db_type_placeholder($schema['fields'][$field]['type']);
}
}
@@ -450,8 +481,8 @@ function services_resource_build_index_query($schema, $order, $page, $fields, $p
$where = !empty($where) ? ' WHERE '. implode(' AND ', $where) : '';
// Run through db_rewrite_sql to make sure proper access checks are applied.
- $sql = "SELECT $fields FROM {$table} $where ORDER BY $order";
- $sql = db_rewrite_sql($sql);
+ $sql = "SELECT $fields FROM {{$table}} AS $primary_table $where ORDER BY $order";
+ $sql = db_rewrite_sql($sql, $primary_table, $primary_field);
$result = db_query_range($sql, $parameters, $page * 20, 20);
return $result;
}
diff --git a/services.resource_build.inc b/services.resource_build.inc
index 0a25baf..b5937d4 100644
--- a/services.resource_build.inc
+++ b/services.resource_build.inc
@@ -110,7 +110,7 @@ function _services_apply_endpoint(&$resources, $endpoint, $strict = TRUE) {
}
}
- $classes = array('targeted actions', 'actions', 'relationships');
+ $classes = array('targeted_actions', 'actions', 'relationships');
foreach ($classes as $class) {
if (!empty($resource[$class])) {
foreach ($resource[$class] as $op => $def) {
@@ -168,9 +168,9 @@ function _services_process_resource($name, &$resource, $controllers) {
}
}
- if (isset($resource['targeted actions'])) {
- foreach ($resource['targeted actions'] as $actname => $act) {
- $controllers[$name . '/targeted_action/' . $actname] = &$resource['actions'][$actname];
+ if (isset($resource['targeted_actions'])) {
+ foreach ($resource['targeted_actions'] as $actname => $act) {
+ $controllers[$name . '/targeted_actions/' . $actname] = &$resource['actions'][$actname];
}
}
return $controllers;
diff --git a/services.runtime.inc b/services.runtime.inc
index 643547c..9d31cfe 100644
--- a/services.runtime.inc
+++ b/services.runtime.inc
@@ -94,7 +94,8 @@ class ServicesArgumentException extends ServicesException {
* services-specific authentication checks. Access checks will always be
* made.
*/
-function services_controller_execute($controller, $args = array(), $auth_args = array(), $options = array()) {
+function services_controller_execute($controller, $args = array(), $options = array()) {
+ global $user;
// Check for missing arguments.
$server_info = services_server_info_object();
if ($server_info->debug) {
@@ -102,13 +103,20 @@ function services_controller_execute($controller, $args = array(), $auth_args =
watchdog('services', 'Passed arguments: <pre>@arguments</pre>', array('@arguments' => print_r($args, TRUE)), WATCHDOG_DEBUG);
}
+ $original_user = $user;
+ $old_state = session_save_session();
+ session_save_session(FALSE);
+ $user = drupal_anonymous_user();
+
+ services_set_server_info('original_user', $original_user);
+
// Check authentication
if (!isset($options['skip_authentication']) || !$options['skip_authentication']) {
$endpoint_name = services_get_server_info('endpoint');
$endpoint = services_endpoint_load($endpoint_name);
foreach ($endpoint->authentication as $auth_module => $settings) {
- if (isset($settings) && $auth_error = services_auth_invoke($auth_module, 'authenticate_call', $settings, $controller, $args, $auth_args)) {
+ if (isset($settings) && $auth_error = services_auth_invoke($auth_module, 'authenticate_call', $settings, $controller, $args)) {
return services_error($auth_error, 401);
}
}
@@ -168,7 +176,11 @@ function services_controller_execute($controller, $args = array(), $auth_args =
$result = call_user_func_array($callable, array($args, $controller, $result));
}
}
-
+
+ if (session_save_session($user) === FALSE) {
+ $user = $original_user;
+ session_save_session($old_state);
+ }
return $result;
}
@@ -243,6 +255,14 @@ function services_auth_invoke($module, $method, &$arg1 = NULL, &$arg2 = NULL, &$
* Returns the formatted resource uri, or NULL if no formatter has been registered.
*/
function services_resource_uri($path) {
+ //We need to use the alias if it exists.
+ $endpoint_name = services_get_server_info('endpoint');
+ $endpoint = services_endpoint_load($endpoint_name);
+ if (isset($endpoint) && !empty($endpoint)) {
+ if (is_array($endpoint->resources) && is_array($path) && isset($path[0]) && isset($endpoint->resources[$path[0]]['alias'])) {
+ $path[0] = $endpoint->resources[$path[0]]['alias'];
+ }
+ }
$formatter = services_get_server_info('resource_uri_formatter');
if ($formatter) {
return call_user_func($formatter, $path);
diff --git a/services.servers.api.php b/services.servers.api.php
index dff762b..f5978ef 100644
--- a/services.servers.api.php
+++ b/services.servers.api.php
@@ -17,10 +17,17 @@
* An associative array with the following keys.
*
* - name: The display name of this server.
+ * - settings: an assoc array containing settings information per endpoint that this server is enabled.
*/
function hook_server_info() {
return array(
'name' => 'REST',
+ 'path' => 'rest',
+ 'settings' => array(
+ 'file' => array('inc', 'rest_server'),
+ 'form' => '_rest_server_settings',
+ 'submit' => '_rest_server_settings_submit',
+ ),
);
}
@@ -32,5 +39,16 @@ function hook_server_info() {
* servers.
*/
function hook_server() {
-
+ $endpoint_path = services_get_server_info('endpoint_path', 'services/rest');
+ $canonical_path = trim(drupal_substr($_GET['q'], drupal_strlen($endpoint_path)), '/');
+ $canonical_path = explode('/', $_GET['q']);
+ $endpoint_path_count = count(explode('/', $endpoint_path));
+ for ($x = 0; $x < $endpoint_path_count; $x++) {
+ array_shift($canonical_path);
+ }
+ $canonical_path = implode('/', $canonical_path);
+ if (empty($canonical_path)) {
+ return '';
+ }
+ //Handle server based on $canonical_path
}
\ No newline at end of file
diff --git a/services.services.api.php b/services.services.api.php
index 784b93c..031f7a4 100644
--- a/services.services.api.php
+++ b/services.services.api.php
@@ -18,7 +18,7 @@
* @return
* An associative array which defines available resources.
*
- * The associative array which defines services has six possible top
+ * The associative array which defines services has seven possible top
* level keys:
*
* - create
@@ -26,10 +26,12 @@
* - update
* - delete
* - actions
- * - targeted actions
+ * - targeted_actions
+ * - relationships
+ *
*
* The first four (the CRUD functions) define the indvidual service
- * callbacks for each function. However 'actions' and 'targeted actions'
+ * callbacks for each function. However 'actions' and 'targeted_actions'
* can contain multiple callbacks.
*
* For those familiar with Services 2.x, these callbacks are created
@@ -62,57 +64,171 @@
* - default value: this is a value that will be passed to the method for this particular argument if no argument value is passed
*/
function hook_services_resources() {
- return array(
- 'user' => array(
- 'file' => array('type' => 'inc', 'module' => 'user_resource'),
+$node_resource = array(
+ 'node' => array(
'retrieve' => array(
- 'help' => 'Retrieves a user',
- 'callback' => '_user_resource_retrieve',
- 'access arguments' => array('access user profiles'), // this is probably not enough, doesn't block things like pass and email
- 'access arguments append' => TRUE,
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'callback' => '_node_resource_retrieve',
'args' => array(
array(
- 'name' => 'uid',
+ 'name' => 'nid',
+ 'optional' => FALSE,
+ 'source' => array('path' => 0),
'type' => 'int',
- 'description' => 'The uid of the user to retrieve.',
- 'source' => array('path' => '0'),
+ 'description' => 'The nid of the node to get',
+ ),
+ ),
+ 'access callback' => '_node_resource_access',
+ 'access arguments' => array('view'),
+ 'access arguments append' => TRUE,
+ ),
+ 'create' => array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'callback' => '_node_resource_create',
+ 'args' => array(
+ array(
+ 'name' => 'node',
'optional' => FALSE,
- 'default value' => NULL,
+ 'source' => 'data',
+ 'description' => 'The node data to create',
+ 'type' => 'array',
),
),
+ 'access callback' => '_node_resource_access',
+ 'access arguments' => array('create'),
+ 'access arguments append' => TRUE,
),
- ),
-
- 'actions' => array(
- 'login' => array(
- 'help' => 'Login a user for a new session',
- 'callback' => '_user_resource_login',
+ 'update' => array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'callback' => '_node_resource_update',
'args' => array(
array(
- 'name' => 'username',
- 'type' => 'string',
- 'description' => 'A valid username',
- 'source' => array('data'),
+ 'name' => 'nid',
'optional' => FALSE,
+ 'source' => array('path' => 0),
+ 'type' => 'int',
+ 'description' => 'The nid of the node to get',
),
array(
- 'name' => 'password',
- 'type' => 'string',
- 'description' => 'A valid password',
- 'source' => array('data'),
+ 'name' => 'node',
'optional' => FALSE,
+ 'source' => 'data',
+ 'description' => 'The node data to update',
+ 'type' => 'array',
),
),
+ 'access callback' => '_node_resource_access',
+ 'access arguments' => array('update'),
+ 'access arguments append' => TRUE,
),
-
- 'logout' => array(
- 'help' => 'Logout a user session',
- 'callback' => '_user_resource_logout',
+ 'delete' => array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'callback' => '_node_resource_delete',
+ 'args' => array(
+ array(
+ 'name' => 'nid',
+ 'optional' => FALSE,
+ 'source' => array('path' => 0),
+ 'type' => 'int',
+ ),
+ ),
+ 'access callback' => '_node_resource_access',
+ 'access arguments' => array('delete'),
+ 'access arguments append' => TRUE,
+ ),
+ 'index' => array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'callback' => '_node_resource_index',
'args' => array(
array(
+ 'name' => 'page',
+ 'optional' => TRUE,
+ 'type' => 'int',
+ 'description' => 'The zero-based index of the page to get, defaults to 0.',
+ 'default value' => 0,
+ 'source' => array('param' => 'page'),
+ ),
+ array(
+ 'name' => 'fields',
+ 'optional' => TRUE,
+ 'type' => 'string',
+ 'description' => 'The fields to get.',
+ 'default value' => '*',
+ 'source' => array('param' => 'fields'),
+ ),
+ array(
+ 'name' => 'parameters',
+ 'optional' => TRUE,
+ 'type' => 'array',
+ 'description' => 'Parameters array',
+ 'default value' => array(),
+ 'source' => array('param' => 'parameters'),
+ ),
+ ),
+ 'access arguments' => array('access content'),
+ ),
+ 'relationships' => array(
+ 'files' => array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'help' => t('This method returns files associated with a node.'),
+ 'access callback' => '_node_resource_access',
+ 'access arguments' => array('view'),
+ 'access arguments append' => TRUE,
+ 'callback' => '_node_resource_load_node_files',
+ 'args' => array(
+ array(
+ 'name' => 'nid',
+ 'optional' => FALSE,
+ 'source' => array('path' => 0),
+ 'type' => 'int',
+ 'description' => 'The nid of the node whose files we are getting',
+ ),
+ array(
+ 'name' => 'file_contents',
+ 'type' => 'int',
+ 'description' => t('To return file contents or not.'),
+ 'source' => array('path' => 2),
+ 'optional' => TRUE,
+ 'default value' => TRUE,
+ ),
),
),
),
),
);
+ if (module_exists('comment')) {
+ $comments = array(
+ 'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/node_resource'),
+ 'help' => t('This method returns the number of new comments on a given node.'),
+ 'access callback' => 'user_access',
+ 'access arguments' => array('access comments'),
+ 'access arguments append' => FALSE,
+ 'callback' => '_node_resource_load_node_comments',
+ 'args' => array(
+ array(
+ 'name' => 'nid',
+ 'type' => 'int',
+ 'description' => t('The node id to load comments for.'),
+ 'source' => array('path' => 0),
+ 'optional' => FALSE,
+ ),
+ array(
+ 'name' => 'count',
+ 'type' => 'int',
+ 'description' => t('Number of comments to load.'),
+ 'source' => array('param' => 'count'),
+ 'optional' => TRUE,
+ ),
+ array(
+ 'name' => 'offset',
+ '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.'),
+ 'source' => array('param' => 'offset'),
+ 'optional' => TRUE,
+ ),
+ ),
+ );
+ $node_resource['node']['relationships']['comments'] = $comments;
+ }
+ return $node_resource;
}
diff --git a/tests/functional/ServicesEndpointTests.test b/tests/functional/ServicesEndpointTests.test
index 3e3dba6..5172299 100644
--- a/tests/functional/ServicesEndpointTests.test
+++ b/tests/functional/ServicesEndpointTests.test
@@ -83,34 +83,6 @@ class ServicesEndpointTests extends ServicesWebTestCase {
$this->assertText('Path to endpoint field is required.',
t('Endpoint path missing error message.')) ;
- $this->assertFieldByName('title', $edit['title'],
- t('Title field remains.')) ;
- $this->assertFieldByName('server', 'rest_server',
- t('Server is rest server')) ;
- $this->assertFieldChecked('edit-services-use-content-permissions',
- t('Storage use content permission is checked.')) ;
- }
-
- /**
- * Test missing title for endpoint causes an error.
- */
- public function testMissingTitle() {
- $edit = $this->populateEndpointFAPI() ;
- unset($edit['title']) ;
- // Create and log in our privileged user.
- $this->privilegedUser = $this->drupalCreateUser(array(
- 'administer services',
- 'administer nodes',
- 'administer site configuration',
- ));
- $this->drupalLogin($this->privilegedUser);
- $this->drupalPost('admin/build/services/add', $edit, t('Save')) ;
- $this->assertResponse('200', 'expected 200');
-
- $this->assertText('Endpoint title field is required.',
- t('Endpoint title missing error message.')) ;
- $this->assertFieldByName('name', $edit['name'],
- t('Name field remains.')) ;
$this->assertFieldByName('server', 'rest_server',
t('Server is rest server')) ;
$this->assertFieldChecked('edit-services-use-content-permissions',
@@ -138,8 +110,6 @@ class ServicesEndpointTests extends ServicesWebTestCase {
t('Server missing error message.'));
$this->assertFieldByName('name', $edit['name'],
t('Name field remains.'));
- $this->assertFieldByName('title', $edit['title'],
- t('Title field remains.'));
$this->assertFieldChecked('edit-services-use-content-permissions',
t('Storage use content permission is checked.')) ;
}
@@ -159,7 +129,6 @@ class ServicesEndpointTests extends ServicesWebTestCase {
public function populateEndpointFAPI() {
return array(
'name' => 'machinename',
- 'title' => $this->randomName(20),
'path' => $this->randomName(10),
'server' => 'rest_server',
'services_use_content_permissions' => TRUE,
@@ -172,7 +141,6 @@ class ServicesEndpointTests extends ServicesWebTestCase {
$endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
$endpoint->api_version = 3;
$endpoint->name = $edit['name'];
- $endpoint->title = $edit['title'];
$endpoint->server = $edit['server'];
$endpoint->path = $edit['path'];
$endpoint->authentication = array(
diff --git a/tests/functional/ServicesParserTests.test b/tests/functional/ServicesParserTests.test
new file mode 100644
index 0000000..183feed
--- /dev/null
+++ b/tests/functional/ServicesParserTests.test
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Call the endpoint tests when no authentication is being used.
+ *
+ */
+
+/**
+ * Run test cases for the endpoint with no authentication turned on.
+ *
+ */
+class ServicesParserTests extends ServicesWebTestCase {
+ // Class variables
+ protected $privilegedUser = NULL ;
+ // Endpoint details.
+ protected $endpoint = NULL;
+
+ /**
+ * Implementation of setUp().
+ */
+ public function setUp() {
+ parent::setUp(
+ 'ctools',
+ 'services',
+ 'rest_server'
+ );
+ // Set up endpoint with disabled 'application/x-www-form-urlencoded' parser.
+ $edit = $this->populateEndpointFAPI() ;
+ $endpoint = new stdClass;
+ $endpoint->disabled = FALSE;
+ $endpoint->api_version = 3;
+ $endpoint->name = $edit['name'];
+ $endpoint->title = $edit['title'];
+ $endpoint->server = $edit['server'];
+ $endpoint->path = $edit['path'];
+ $endpoint->authentication = array(
+ 'services' => 'services',
+ );
+ $endpoint->server_settings = array(
+ 'rest_server' => array(
+ 'formatters' => array(
+ 'php' => TRUE,
+ ),
+ 'parsers' => array(
+ 'application/x-yaml' => TRUE,
+ 'application/json' => TRUE,
+ 'application/vnd.php.serialized' => TRUE,
+ 'application/plist' => TRUE,
+ 'application/plist+xml' => TRUE,
+ 'application/x-www-form-urlencoded' => FALSE,
+ ),
+ ),
+ );
+ $endpoint->resources = array(
+ 'user' => array(
+ 'actions' => array(
+ 'login' => array(
+ 'enabled' => 1,
+ ),
+ 'logout' => array(
+ 'enabled' => 1,
+ ),
+ ),
+ ),
+ );
+ $endpoint->debug = 1;
+ $endpoint->export_type = FALSE;
+ services_endpoint_save($endpoint);
+ $endpoint = services_endpoint_load($endpoint->name);
+ $this->assertTrue($endpoint->name == $edit['name'], t('Endpoint successfully created'));
+ $this->endpoint = $endpoint;
+ }
+
+ /**
+ * Implementation of getInfo().
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => t('Parser'),
+ 'description' => t('Test the Parser functionality.'),
+ 'group' => t('Services'),
+ );
+ }
+
+ /**
+ * Testing parser functionality.
+ */
+ public function testParser() {
+ $account = $this->drupalCreateUser();
+
+ // Logout first.
+ $this->drupalLogout();
+
+ // Try to login. By default servicesPost uses
+ // 'application/x-www-form-urlencoded' type. So it should be refused.
+ $response = $this->servicesPost($this->endpoint->path . '/user/login', array('username' => $account->name, 'password' => $account->pass_raw));
+
+ $this->assertTrue(strpos($response['header'], '406 Not Acceptable: Unsupported request content type application/x-www-form-urlencoded') !== FALSE,
+ t('Do not accept application/x-www-form-urlencoded if disabled.'), 'Parser');
+ }
+
+}
\ No newline at end of file
diff --git a/tests/functional/ServicesResourceCommentTests.test b/tests/functional/ServicesResourceCommentTests.test
index c2e093b..86cac39 100644
--- a/tests/functional/ServicesResourceCommentTests.test
+++ b/tests/functional/ServicesResourceCommentTests.test
@@ -66,7 +66,7 @@ class ServicesResourceCommentTests extends ServicesWebtestCase {
'subject' => $this->randomString(),
'comment' => $this->randomString(),
);
- $response = $this->servicesPost($path . '/comment', array('comment' => $comment));
+ $response = $this->servicesPost($path . '/comment', $comment);
$cid = $response['body']['cid'];
$comment['cid'] = $cid;
@@ -85,10 +85,54 @@ class ServicesResourceCommentTests extends ServicesWebtestCase {
// Full HTML format.
'format' => 2,
);
+ $response_array = $this->servicesPost($this->endpoint->path . '/comment', $comment);
+
+ $new_comment = _comment_load($response_array['body']['cid']);
+ $this->assertNotEqual($new_comment->format, $comment['format'], t('Full HTML format has not been applied.'), 'CommentResource: Create');
+ }
+
+ /**
+ * Test create comment (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testCommentCreateLegacy() {
+ $path = $this->endpoint->path;
+
+ // Create node with commenting.
+ $settings = array('comment' => COMMENT_NODE_READ_WRITE);
+ $node = $this->drupalCreateNode($settings);
+
+ $comment = array(
+ 'uid' => $this->privileged_user->uid,
+ 'nid' => $node->nid,
+ 'subject' => $this->randomString(),
+ 'comment' => $this->randomString(),
+ );
+ $response = $this->servicesPost($path . '/comment', array('comment' => $comment));
+
+ $cid = $response['body']['cid'];
+ $comment['cid'] = $cid;
+
+ $comment_load = (array)_comment_load($cid);
+ $comment_intersect = array_intersect_assoc($comment_load, $comment);
+
+ $this->assertEqual($comment, $comment_intersect, t('Comment created properly.'), 'CommentResource: Create (Legacy)');
+
+ // Try to create node with not allowed filter.
+ $comment = array(
+ 'uid' => $this->privileged_user->uid,
+ 'nid' => $node->nid,
+ 'subject' => $this->randomString(),
+ 'comment' => $this->randomString(),
+ // Full HTML format.
+ 'format' => 2,
+ );
$response_array = $this->servicesPost($this->endpoint->path . '/comment', array('comment' => $comment));
$new_comment = _comment_load($response_array['body']['cid']);
- $this->assertNotEqual($new_comment->format, $comment->format, t('Full HTML format has not been applied.'), 'CommentResource: Create');
+ $this->assertNotEqual($new_comment->format, $comment['format'], t('Full HTML format has not been applied.'), 'CommentResource: Create (Legacy)');
}
/**
@@ -144,7 +188,7 @@ class ServicesResourceCommentTests extends ServicesWebtestCase {
$comment_update['subject'] = $this->randomString();
$comment_update['comment'] = $this->randomString();
- $response = $this->servicesPut($path . '/comment/' . $cid, array('data' => $comment_update));
+ $response = $this->servicesPut($path . '/comment/' . $cid, $comment_update);
$comment_load = (array)_comment_load($cid);
@@ -154,9 +198,12 @@ class ServicesResourceCommentTests extends ServicesWebtestCase {
}
/**
- * Test delete method.
+ * Test update method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
*/
- function testCommentDelete() {
+ function testCommentUpdateLegacy() {
$path = $this->endpoint->path;
// Create node with commenting.
@@ -173,65 +220,44 @@ class ServicesResourceCommentTests extends ServicesWebtestCase {
$cid = comment_save((array) $comment);
$comment['cid'] = $cid;
- $response = $this->servicesDelete($path . '/comment/' . $cid);
+ $comment_update = $comment;
+ $comment_update['subject'] = $this->randomString();
+ $comment_update['comment'] = $this->randomString();
- $comment_load = _comment_load($cid);
+ $response = $this->servicesPut($path . '/comment/' . $cid, array('data' => $comment_update));
- $this->assertTrue(empty($comment_load), t('Comment deleted properly.'), 'CommentResource: Delete');
+ $comment_load = (array)_comment_load($cid);
+
+ $comment_intersect = array_intersect_assoc($comment_load, $comment_update);
+
+ $this->assertEqual($comment_update, $comment_intersect, t('Comment updated properly.'), 'CommentResource: Update (legacy)');
}
/**
- * Test loadNodeComments method.
+ * Test delete method.
*/
- function testCommentLoadNodeComments() {
+ function testCommentDelete() {
$path = $this->endpoint->path;
// Create node with commenting.
$settings = array('comment' => COMMENT_NODE_READ_WRITE);
$node = $this->drupalCreateNode($settings);
- $nid = $node->nid;
-
- // Generate 15 comments for node.
- $comments = array();
- for ($i = 0; $i < 15; $i++) {
- $comment = array(
- 'uid' => $this->privileged_user->uid,
- 'nid' => $nid,
- 'subject' => $this->randomString(),
- 'comment' => $this->randomString(),
- );
-
- $cid = comment_save((array) $comment);
-
- $comments[] = _comment_load($cid);
- }
- $comments = array_reverse($comments);
- // Generate some comments for another node.
- $settings = array('comment' => COMMENT_NODE_READ_WRITE);
- $node2 = $this->drupalCreateNode($settings);
- for ($i = 0; $i < 5; $i++) {
- $comment = array(
- 'uid' => $this->privileged_user->uid,
- 'nid' => $node2->nid,
- 'subject' => $this->randomString(),
- 'comment' => $this->randomString(),
- );
+ $comment = array(
+ 'uid' => $this->privileged_user->uid,
+ 'nid' => $node->nid,
+ 'subject' => $this->randomString(),
+ 'comment' => $this->randomString(),
+ );
- $cid = comment_save((array) $comment);
- }
+ $cid = comment_save((array) $comment);
+ $comment['cid'] = $cid;
- // Load all comments of the first node.
- $response = $this->servicesPost($path . '/comment/loadNodeComments', array('nid' => $nid));
- $this->assertEqual(array_slice($comments, 0, 10), $response['body'], t('Received all 15 comments.'), 'CommentResource: loadNodeComments');
+ $response = $this->servicesDelete($path . '/comment/' . $cid);
- // Load only 5 comments of the first node.
- $response = $this->servicesPost($path . '/comment/loadNodeComments', array('nid' => $nid, 'count' => 5));
- $this->assertEqual(array_slice($comments, 0, 5), $response['body'], t('Received last 5 comments.'), 'CommentResource: loadNodeComments');
+ $comment_load = _comment_load($cid);
- // Load only 5 comments of the first node starting from fifth comment.
- $response = $this->servicesPost($path . '/comment/loadNodeComments', array('nid' => $nid, 'count' => 5, 'start' => 5));
- $this->assertEqual(array_slice($comments, 5, 5), $response['body'], t('Received 5 comments starting from fifth comment.'), 'CommentResource: loadNodeComments');
+ $this->assertTrue(empty($comment_load), t('Comment deleted properly.'), 'CommentResource: Delete');
}
/**
diff --git a/tests/functional/ServicesResourceFileTests.test b/tests/functional/ServicesResourceFileTests.test
index f2e750f..5d762be 100644
--- a/tests/functional/ServicesResourceFileTests.test
+++ b/tests/functional/ServicesResourceFileTests.test
@@ -77,7 +77,7 @@ class ServicesResourceFileTests extends ServicesWebTestCase {
);
// Create file with call.
- $result = $this->servicesPost($this->endpoint->path . '/file', array('file' => $file));
+ $result = $this->servicesPost($this->endpoint->path . '/file', $file);
$this->assertEqual($result['code'], 200, t('File created.'), 'FileResource: Create');
// Load file and assert that it exists.
@@ -88,7 +88,7 @@ class ServicesResourceFileTests extends ServicesWebTestCase {
// Lets create another file with the same details
// and ensure name and path are changed automatically.
- $result = $this->servicesPost($this->endpoint->path . '/file', array('file' => $file));
+ $result = $this->servicesPost($this->endpoint->path . '/file', $file);
$dbresult = db_query('SELECT * FROM {files} WHERE fid = %d', $result['body']['fid']);
$file1 = db_fetch_object($dbresult);
$file2 = db_fetch_object($dbresult);
@@ -97,6 +97,41 @@ class ServicesResourceFileTests extends ServicesWebTestCase {
}
/**
+ * Test create method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ public function testResourceFileCreateLegacy() {
+ // Create file argument with data.
+ $file = array(
+ 'filesize' => filesize($this->testfiles[0]->filename),
+ 'filename' => $this->testfiles[0]->filename,
+ 'file' => base64_encode(file_get_contents($this->testfiles[0]->filename)),
+ 'uid' => $this->privileged_user->uid,
+ );
+
+ // Create file with call.
+ $result = $this->servicesPost($this->endpoint->path . '/file', array('file' => $file));
+ $this->assertEqual($result['code'], 200, t('File created.'), 'FileResource: Create (Legacy)');
+
+ // Load file and assert that it exists.
+ //$file_load = file_load($result['body']['fid']);
+ $dbresult = db_query('SELECT * FROM {files} WHERE fid = %d', $result['body']['fid']);
+ $file_load = db_fetch_object($dbresult);
+ $this->assertTrue(is_file($file_load->filepath), t('New file saved to disk.'), 'FileResource: Create (Legacy)');
+
+ // Lets create another file with the same details
+ // and ensure name and path are changed automatically.
+ $result = $this->servicesPost($this->endpoint->path . '/file', array('file' => $file));
+ $dbresult = db_query('SELECT * FROM {files} WHERE fid = %d', $result['body']['fid']);
+ $file1 = db_fetch_object($dbresult);
+ $file2 = db_fetch_object($dbresult);
+ $this->assertTrue($file1->filename != $file2->filename && $file1->filepath != $file2->filepath,
+ t('Two identical files created end up with different names.'), 'FileResource: Create (Legacy)');
+ }
+
+ /**
* Test retrieve method.
*/
public function testResourceFileRetrieve() {
diff --git a/tests/functional/ServicesResourceNodeTests.test b/tests/functional/ServicesResourceNodeTests.test
index 76275f2..d93568f 100644
--- a/tests/functional/ServicesResourceNodeTests.test
+++ b/tests/functional/ServicesResourceNodeTests.test
@@ -98,7 +98,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'name' => $this->privilegedUser->name,
);
- $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+ $responseArray = $this->servicesPost($this->endpoint->path . '/node', $node);
$nodeResourceCreateReturn = $responseArray['body'];
$this->assertTrue(isset($nodeResourceCreateReturn['nid']), t('Node was successfully created'), 'NodeResource: Create');
@@ -110,6 +110,37 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
}
/**
+ * Testing node_resource Create (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ public function testEndpointResourceNodeCreateLegacy() {
+ // Create and log in our privileged user.
+ $this->privilegedUser = $this->drupalCreateUser(array(
+ 'administer services',
+ 'administer nodes',
+ ));
+ $this->drupalLogin($this->privilegedUser);
+ $node = array(
+ 'title' => 'testing',
+ 'body' => 'bodytest',
+ 'type' => 'story',
+ 'name' => $this->privilegedUser->name,
+ );
+
+ $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+ $nodeResourceCreateReturn = $responseArray['body'];
+
+ $this->assertTrue(isset($nodeResourceCreateReturn['nid']), t('Node was successfully created'), 'NodeResource: Create (Legacy)');
+ if (isset($nodeResourceCreateReturn['nid'])) {
+ $newNode = node_load($nodeResourceCreateReturn['nid']);
+ $this->assertTrue($newNode->title = $node['title'], t('Title was the same'), 'NodeResource: Create (Legacy)');
+ $this->assertTrue($newNode->body = $node['body'], t('Body was the same'), 'NodeResource: Create (Legacy)');
+ }
+ }
+
+ /**
* testing node_resource Created make ure it fails with no perms
*/
public function testEndpointResourceNodeCreateFail() {
@@ -125,7 +156,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'name' => $this->privilegedUser->name,
);
- $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+ $responseArray = $this->servicesPost($this->endpoint->path . '/node', $node);
$this->assertTrue($responseArray['code'] == 401, t('User with not sufficient permissions cannot create node'), 'NodeResource: Create');
}
@@ -148,7 +179,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'type' => 'page',
);
- $responseArray = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+ $responseArray = $this->servicesPost($this->endpoint->path . '/node', $node);
$nodeResourceUpdateReturn = $responseArray['body'];
$nodeAfterUpdate = node_load($nodeResourceUpdateReturn);
@@ -195,7 +226,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
)),
);
- $response = $this->servicesPost($this->endpoint->path . '/node', array('node' => $node));
+ $response = $this->servicesPost($this->endpoint->path . '/node', $node);
// Get number of attached taxonomy terms from this node. We do it manually
// as we cannot get terms on node_load as as empty array is statically
@@ -303,9 +334,10 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
$this->assertTrue(isset($result['body'][$testfile1['fid']]) && isset($result['body'][$testfile2['fid']]) && !isset($result['body'][$testfile3['fid']]),
t('Attached files listed.'), 'FileResource: nodeFiles');
}
+
/**
- * testing node_resource Update
- */
+ * Testing node_resource Update
+ */
public function testEndpointResourceNodeUpdate() {
// Create and log in our privileged user.
$this->privilegedUser = $this->drupalCreateUser(array(
@@ -321,7 +353,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'name' => $this->privilegedUser->name,
);
- $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+ $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, $node_update);
$nodeAfterUpdate = node_load($responseArray['body']['nid']);
$this->assertTrue(isset($nodeAfterUpdate->nid), t('Node was successfully updated'), 'NodeResource: Updated');
if (isset($nodeAfterUpdate->nid)) {
@@ -331,6 +363,36 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
}
/**
+ * Testing node_resource Update (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ public function testEndpointResourceNodeUpdateLegacy() {
+ // Create and log in our privileged user.
+ $this->privilegedUser = $this->drupalCreateUser(array(
+ 'administer services',
+ 'administer nodes',
+ ));
+ $this->drupalLogin($this->privilegedUser);
+ $node = $this->drupalCreateNode();
+ $node_update = array(
+ 'title' => 'testing',
+ 'body' => 'bodytest',
+ 'type' => 'story',
+ 'name' => $this->privilegedUser->name,
+ );
+
+ $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+ $nodeAfterUpdate = node_load($responseArray['body']['nid']);
+ $this->assertTrue(isset($nodeAfterUpdate->nid), t('Node was successfully updated'), 'NodeResource: Updated (Legacy)');
+ if (isset($nodeAfterUpdate->nid)) {
+ $this->assertTrue($nodeAfterUpdate->title == $node_update['title'], t('Title was the same'), 'NodeResource: Update (Legacy)');
+ $this->assertTrue($nodeAfterUpdate->body == $node_update['body'], t('Body was the same'), 'NodeResource: Update (Legacy)');
+ }
+ }
+
+ /**
* testing node_resource Update fail with no permissions
*/
public function testEndpointResourceNodeUpdatePermFail() {
@@ -352,7 +414,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'body' => 'bodytest',
'type' => 'story',
);
- $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+ $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, $node_update);
$this->assertTrue(strpos($responseArray['status'], 'Access denied for user'), t('Updating the node failed without needed permissions. This is good!'), 'NodeResource: Update');
}
@@ -375,7 +437,7 @@ class ServicesResourceNodetests extends ServicesWebtestCase {
'type' => 'story',
);
- $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, array('node' => $node_update));
+ $responseArray = $this->servicesPut($this->endpoint->path . '/node/' . $node->nid, $node_update);
$this->assertTrue(strpos($responseArray['status'], 'Title field is required.'), t('Node was not updated without title.'), 'NodeResource: Update');
}
diff --git a/tests/functional/ServicesResourceTaxonomyTests.test b/tests/functional/ServicesResourceTaxonomyTests.test
index 1bbf87e..3aecac0 100644
--- a/tests/functional/ServicesResourceTaxonomyTests.test
+++ b/tests/functional/ServicesResourceTaxonomyTests.test
@@ -67,7 +67,7 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
'weight' => 0,
);
- $response = $this->servicesPost($path . '/taxonomy_vocabulary', array('vocabulary' => $vocabulary));
+ $response = $this->servicesPost($path . '/taxonomy_vocabulary', $vocabulary);
$vid = db_result(db_query('SELECT vid FROM {vocabulary} WHERE name = "%s"', $vocabulary['name']));
@@ -78,6 +78,36 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
}
/**
+ * Test taxonomy vocabulary create method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testVocabularyCreateLegacy() {
+ $path = $this->endpoint->path;
+
+ $vocabulary = array(
+ 'name' => $this->randomName(),
+ 'description' => $this->randomString(),
+ 'help' => $this->randomString(),
+ 'relations' => 1,
+ 'hierarchy' => 1,
+ 'multiple' => 1,
+ 'required' => 0,
+ 'module' => 'services',
+ 'weight' => 0,
+ );
+
+ $response = $this->servicesPost($path . '/taxonomy_vocabulary', array('vocabulary' => $vocabulary));
+
+ $vid = db_result(db_query('SELECT vid FROM {vocabulary} WHERE name = "%s"', $vocabulary['name']));
+
+ $vocabulary_load = (array)taxonomy_vocabulary_load($vid);
+ $vocabulary_intersect = array_intersect_assoc($response['body'], $vocabulary_load);
+ $this->assertEqual($vocabulary['name'], $response['body']['name'], t('Taxonomy vocabulary created properly.'), 'TaxonomyVocabularyResource: Create (Legacy)');
+ }
+
+ /**
* Test taxonomy vocabulry retrieve method.
*/
function testVocabularyRetrieve() {
@@ -106,7 +136,7 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
$vocabulary['name'] = $this->randomName();
$vocabulary['description'] = $this->randomString();
- $response = $this->servicesPUT($path . '/taxonomy_vocabulary/' . $vid, array('vocabulary' => $vocabulary));
+ $response = $this->servicesPUT($path . '/taxonomy_vocabulary/' . $vid, $vocabulary);
$vocabulary_load = (array)taxonomy_vocabulary_load($vid, TRUE);
@@ -115,6 +145,29 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
}
/**
+ * Test taxonomy vocabulary update (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testVocabularyUpdateLegacy() {
+ $path = $this->endpoint->path;
+
+ $vocabulary = $this->createVocabulary();
+ $vid = $vocabulary['vid'];
+
+ $vocabulary['name'] = $this->randomName();
+ $vocabulary['description'] = $this->randomString();
+
+ $response = $this->servicesPUT($path . '/taxonomy_vocabulary/' . $vid, array('vocabulary' => $vocabulary));
+
+ $vocabulary_load = (array)taxonomy_vocabulary_load($vid, TRUE);
+
+ $vocabulary_intersect = array_intersect_assoc($vocabulary, $vocabulary_load);
+ $this->assertEqual($vocabulary, $vocabulary_intersect, t('Taxonomy vocabulary updated properly.'), 'TaxonomyVocabularyResource: Update (Legacy)');
+ }
+
+ /**
* Test taxonomy vocabulary delete method.
*/
function testVocabularyDelete() {
@@ -198,7 +251,7 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
'parent' => NULL,
);
- $response = $this->servicesPost($path . '/taxonomy_term', array('term' => $term));
+ $response = $this->servicesPost($path . '/taxonomy_term', $term);
// Load term by name.
$term_by_name = (array)current(taxonomy_get_term_by_name($term['name']));
@@ -212,6 +265,38 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
}
/**
+ * Test taxonomy term create method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testTermCreateLegacy() {
+ $path = $this->endpoint->path;
+
+ $vocabulary = $this->createVocabulary();
+
+ $term = array(
+ 'vid' => $vocabulary['vid'],
+ 'name' => $this->randomName(),
+ 'description' => $this->randomString(),
+ 'weight' => rand(0, 100),
+ 'parent' => NULL,
+ );
+
+ $response = $this->servicesPost($path . '/taxonomy_term', array('term' => $term));
+
+ // Load term by name.
+ $term_by_name = (array)current(taxonomy_get_term_by_name($term['name']));
+ $term_intersect = array_intersect_assoc($term, $term_by_name);
+
+ // As term_intersect will not have parent, we unset this property.
+ $term_data = $term;
+ unset($term_data['parent']);
+
+ $this->assertEqual($term_data, $term_intersect, t('Taxonomy term created properly.'), 'TaxonomyTermResource: Create (Legacy)');
+ }
+
+ /**
* Test taxonomy term retrieve method.
*/
function testTermRetrieve() {
@@ -241,7 +326,7 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
'weight' => rand(0, 100),
);
- $this->servicesPut($path . '/taxonomy_term/' . $term['tid'], array('term' => $term_update_data));
+ $this->servicesPut($path . '/taxonomy_term/' . $term['tid'], $term_update_data);
$term_update = (array)current(taxonomy_get_term_by_name($term_update_data['name']));
@@ -250,6 +335,32 @@ class ServicesResourceTaxonomyTests extends ServicesWebtestCase {
}
/**
+ * Test taxonomy term update method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testTermUpdateLegacy() {
+ $path = $this->endpoint->path;
+
+ $vocabulary = $this->createVocabulary();
+ $term = $this->createTerm($vocabulary['vid']);
+
+ $term_update_data = array(
+ 'name' => $this->randomName(),
+ 'description' => $this->randomString(),
+ 'weight' => rand(0, 100),
+ );
+
+ $this->servicesPut($path . '/taxonomy_term/' . $term['tid'], array('term' => $term_update_data));
+
+ $term_update = (array)current(taxonomy_get_term_by_name($term_update_data['name']));
+
+ // Ensure that terms have different names but same tid.
+ $this->assertTrue(($term['tid'] == $term_update['tid']) && ($term['name'] != $term_update['name']), t('Taxonomy term updated properly.'), 'TaxonomyTermResource: Update (Legacy)');
+ }
+
+ /**
* Test taxonomy term delete method.
*/
function testTermDelete() {
diff --git a/tests/functional/ServicesResourceUserTests.test b/tests/functional/ServicesResourceUserTests.test
index a800a3f..bfc7f3a 100644
--- a/tests/functional/ServicesResourceUserTests.test
+++ b/tests/functional/ServicesResourceUserTests.test
@@ -61,7 +61,7 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
$user['pass'] = user_password();
$user['status'] = 1;
- $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+ $response = $this->servicesPost($this->endpoint->path . '/user', $user);
$account = $response['body'];
$this->assertTrue(!empty($account['uid']), t('User has been create successfully.'), 'UserResource: Create');
@@ -74,11 +74,42 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
$user['name'] = $this->randomName();
$user['pass'] = user_password();
$user['status'] = 1;
- $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+ $response = $this->servicesPost($this->endpoint->path . '/user', $user);
$this->assertTrue(strpos($response['status'], 'E-mail address field is required') !== FALSE, t('It is not possible to create user without email.'), 'UserResource: Create');
}
/**
+ * Test create method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testCreateUserLegacy() {
+ // Create user.
+ $user = array();
+ $user['name'] = $this->randomName();
+ $user['mail'] = $user['name'] . '@example.com';
+ $user['pass'] = user_password();
+ $user['status'] = 1;
+
+ $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+ $account = $response['body'];
+ $this->assertTrue(!empty($account['uid']), t('User has been create successfully.'), 'UserResource: Create (Legacy)');
+
+ // Load user.
+ $user_load = user_load($account['uid']);
+ $this->assertTrue(!empty($user_load), t('Newly created user has been loaded successfully.'), 'UserResource: Create (Legacy)');
+
+ // Try to create user without email.
+ $user = array();
+ $user['name'] = $this->randomName();
+ $user['pass'] = user_password();
+ $user['status'] = 1;
+ $response = $this->servicesPost($this->endpoint->path . '/user', array('account' => $user));
+ $this->assertTrue(strpos($response['status'], 'E-mail address field is required') !== FALSE, t('It is not possible to create user without email.'), 'UserResource: Create (Legacy)');
+ }
+
+ /**
* Test register method.
*
* Register user, load user.
@@ -91,7 +122,7 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
$user['pass'] = user_password();
$user['status'] = 1;
- $response = $this->servicesPost($this->endpoint->path . '/user/register', array('account' => $user));
+ $response = $this->servicesPost($this->endpoint->path . '/user/register', $user);
//Verify logged in users cannnot create accounts
$code = $response['code'];
@@ -100,7 +131,7 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
//Verify logged out state can create users
$this->drupalLogout();
- $response = $this->servicesPost($this->endpoint->path . '/user/register', array('account' => $user));
+ $response = $this->servicesPost($this->endpoint->path . '/user/register', $user);
$account = $response['body'];
$this->assertTrue(!empty($account['uid']), t('User has been create successfully.'), 'UserResource: Create');
@@ -112,6 +143,40 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
}
/**
+ * Test register method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testRegisterUserLegacy() {
+ // Create user.
+ $user = array();
+ $user['name'] = $this->randomName();
+ $user['mail'] = $user['name'] . '@example.com';
+ $user['pass'] = user_password();
+ $user['status'] = 1;
+
+ $response = $this->servicesPost($this->endpoint->path . '/user/register', array('account' => $user));
+
+ //Verify logged in users cannnot create accounts
+ $code = $response['code'];
+ $this->assertEqual($code, '401', t('Verify permission denied 401'), 'UserResource: Create (Legacy)');
+
+ //Verify logged out state can create users
+ $this->drupalLogout();
+
+ $response = $this->servicesPost($this->endpoint->path . '/user/register', array('account' => $user));
+ $account = $response['body'];
+
+ $this->assertTrue(!empty($account['uid']), t('User has been create successfully.'), 'UserResource: Create (Legacy)');
+
+ // Load user.
+ $user_load = user_load($account['uid']);
+ $this->assertTrue(!empty($user_load), t('Newly created user has been loaded successfully.'), 'UserResource: Create (Legacy)');
+ $this->drupalLogin($this->privileged_user);
+ }
+
+ /**
* Test retrieve method.
*/
function testRetrieveUser() {
@@ -141,13 +206,37 @@ class ServicesResourceUsertests extends ServicesWebtestCase {
'roles' => $account->roles,
'mail' => $this->randomName() . '@example.com',
);
- $response = $this->servicesPut($this->endpoint->path . '/user/' . $account->uid, array('data' => $updated_account));
+ $response = $this->servicesPut($this->endpoint->path . '/user/' . $account->uid, $updated_account);
$user_load = user_load($account->uid);
$this->assertEqual($updated_account['mail'], $user_load->mail, t('User details have been updated successfully'), 'UserResource: Update');
}
/**
+ * Test update method (Legacy).
+ *
+ * TODO: To be removed in future version.
+ * @see http://drupal.org/node/1083242
+ */
+ function testUpdateUserLegacy() {
+ // Create user.
+ $account = $this->drupalCreateUser();
+
+ // Update mail of the user. Note: roles is required attribute as update
+ // method does drupal_execute of user_profile_form form.
+ $updated_account = array(
+ 'uid' => $account->uid,
+ 'name' => $account->name,
+ 'roles' => $account->roles,
+ 'mail' => $this->randomName() . '@example.com',
+ );
+ $response = $this->servicesPut($this->endpoint->path . '/user/' . $account->uid, array('data' => $updated_account));
+
+ $user_load = user_load($account->uid);
+ $this->assertEqual($updated_account['mail'], $user_load->mail, t('User details have been updated successfully'), 'UserResource: Update (Legacy)');
+ }
+
+ /**
* Test delete method.
*/
function testDeleteUser() {
diff --git a/tests/functional/ServicesWebTestCase.php b/tests/functional/ServicesWebTestCase.php
index 70f012f..b6547ea 100644
--- a/tests/functional/ServicesWebTestCase.php
+++ b/tests/functional/ServicesWebTestCase.php
@@ -156,7 +156,7 @@ class ServicesWebTestCase extends DrupalWebTestCase {
}
public function saveNewEndpoint() {
- $edit = $this->populateEndpointFAPI() ;
+ $edit = $this->populateEndpointFAPI();
$endpoint = new stdClass;
$endpoint->disabled = FALSE; /* Edit this to true to make a default endpoint disabled initially */
$endpoint->api_version = 3;
@@ -165,11 +165,33 @@ class ServicesWebTestCase extends DrupalWebTestCase {
$endpoint->server = $edit['server'];
$endpoint->path = $edit['path'];
$endpoint->authentication = array(
- 'services_sessauth' => array(),
+ 'services' => 'services',
+ );
+ $endpoint->server_settings = array(
+ 'rest_server' => array(
+ 'formatters' => array(
+ 'json' => TRUE,
+ 'bencode' => TRUE,
+ 'rss' => TRUE,
+ 'plist' => TRUE,
+ 'xmlplist' => TRUE,
+ 'php' => TRUE,
+ 'yaml' => TRUE,
+ 'jsonp' => FALSE,
+ 'xml' => FALSE,
+ ),
+ 'parsers' => array(
+ 'application/x-yaml' => TRUE,
+ 'application/json' => TRUE,
+ 'application/vnd.php.serialized' => TRUE,
+ 'application/plist' => TRUE,
+ 'application/plist+xml' => TRUE,
+ 'application/x-www-form-urlencoded' => TRUE,
+ ),
+ ),
);
$endpoint->resources = array(
- 'node' => array(
- 'alias' => '',
+ 'comment' => array(
'operations' => array(
'create' => array(
'enabled' => 1,
@@ -187,39 +209,37 @@ class ServicesWebTestCase extends DrupalWebTestCase {
'enabled' => 1,
),
),
- 'relationships' => array(
- 'nodefiles' => array(
+ 'actions' => array(
+ 'countAll' => array(
'enabled' => 1,
),
- 'comments' => array(
+ 'countNew' => array(
'enabled' => 1,
),
),
),
- 'system' => array(
- 'alias' => '',
- 'actions' => array(
- 'connect' => array(
+ 'file' => array(
+ 'operations' => array(
+ 'create' => array(
'enabled' => 1,
),
- 'get_variable' => array(
+ 'retrieve' => array(
'enabled' => 1,
),
- 'set_variable' => array(
+ 'delete' => array(
'enabled' => 1,
),
- 'del_variable' => array(
+ 'index' => array(
'enabled' => 1,
),
),
),
- 'taxonomy_term' => array(
- 'alias' => '',
+ 'node' => array(
'operations' => array(
- 'create' => array(
+ 'retrieve' => array(
'enabled' => 1,
),
- 'retrieve' => array(
+ 'create' => array(
'enabled' => 1,
),
'update' => array(
@@ -228,42 +248,41 @@ class ServicesWebTestCase extends DrupalWebTestCase {
'delete' => array(
'enabled' => 1,
),
- ),
- 'actions' => array(
- 'selectNodes' => array(
+ 'index' => array(
'enabled' => 1,
),
),
- ),
- 'taxonomy_vocabulary' => array(
- 'alias' => '',
- 'operations' => array(
- 'create' => array(
+ 'relationships' => array(
+ 'files' => array(
'enabled' => 1,
),
- 'retrieve' => array(
+ 'comments' => array(
'enabled' => 1,
),
- 'update' => array(
+ ),
+ ),
+ 'system' => array(
+ 'actions' => array(
+ 'connect' => array(
'enabled' => 1,
),
- 'delete' => array(
+ 'get_variable' => array(
'enabled' => 1,
),
- ),
- 'actions' => array(
- 'getTree' => array(
+ 'set_variable' => array(
+ 'enabled' => 1,
+ ),
+ 'del_variable' => array(
'enabled' => 1,
),
),
),
- 'user' => array(
- 'alias' => '',
+ 'taxonomy_term' => array(
'operations' => array(
- 'create' => array(
+ 'retrieve' => array(
'enabled' => 1,
),
- 'retrieve' => array(
+ 'create' => array(
'enabled' => 1,
),
'update' => array(
@@ -277,24 +296,17 @@ class ServicesWebTestCase extends DrupalWebTestCase {
),
),
'actions' => array(
- 'login' => array(
- 'enabled' => 1,
- ),
- 'logout' => array(
- 'enabled' => 1,
- ),
- 'register' => array(
+ 'selectNodes' => array(
'enabled' => 1,
),
),
),
- 'comment' => array(
- 'alias' => '',
+ 'taxonomy_vocabulary' => array(
'operations' => array(
- 'create' => array(
+ 'retrieve' => array(
'enabled' => 1,
),
- 'retrieve' => array(
+ 'create' => array(
'enabled' => 1,
),
'update' => array(
@@ -303,41 +315,48 @@ class ServicesWebTestCase extends DrupalWebTestCase {
'delete' => array(
'enabled' => 1,
),
- ),
- 'actions' => array(
- 'countAll' => array(
+ 'index' => array(
'enabled' => 1,
),
- 'countNew' => array(
+ ),
+ 'actions' => array(
+ 'getTree' => array(
'enabled' => 1,
),
),
),
- 'file' => array(
- 'alias' => '',
+ 'user' => array(
'operations' => array(
+ 'retrieve' => array(
+ 'enabled' => 1,
+ ),
'create' => array(
'enabled' => 1,
),
- 'retrieve' => array(
+ 'update' => array(
'enabled' => 1,
),
'delete' => array(
'enabled' => 1,
),
- ),
- ),
- 'echo' => array(
- 'alias' => '',
- 'operations' => array(
'index' => array(
'enabled' => 1,
),
),
+ 'actions' => array(
+ 'login' => array(
+ 'enabled' => 1,
+ ),
+ 'logout' => array(
+ 'enabled' => 1,
+ ),
+ 'register' => array(
+ 'enabled' => 1,
+ ),
+ ),
),
);
$endpoint->debug = 1;
- $endpoint->status = 1;
$endpoint->export_type = FALSE;
services_endpoint_save($endpoint);
$endpoint = services_endpoint_load($endpoint->name);
diff --git a/tests/unit/TestServicesModule.test b/tests/unit/TestServicesModule.test
index 1da24e2..a0cb67b 100644
--- a/tests/unit/TestServicesModule.test
+++ b/tests/unit/TestServicesModule.test
@@ -64,8 +64,8 @@ class ServicesModuleTests extends DrupalWebTestCase {
$message = t('services_perm should return an array') ;
$this->assertTrue(gettype($resultArray)=='array', $message) ;
- $message = t('There should be 6 permission types') ;
- $this->assertEqual(count($resultArray), 6, $message) ;
+ $message = t('There should be 7 permission types') ;
+ $this->assertEqual(count($resultArray), 7, $message) ;
$permission = 'administer services' ;
$this->helperPermExists($resultArray, $permission) ;
@@ -111,8 +111,7 @@ class ServicesModuleTests extends DrupalWebTestCase {
public function testEndpointMenu() {
// Create the endpoint.
$endpointSettings = array(
- 'name' => 'mchnname',
- 'title' => $this->randomName(20),
+ 'name' => $this->randomName(10),
'path' => $this->randomName(10),
'server' => 'rest_server',
'services_use_content_permissions' => TRUE,
@@ -190,7 +189,6 @@ class ServicesModuleTests extends DrupalWebTestCase {
$string = 'New Service object should have property ';
$this->assertTrue(property_exists($results, 'eid'), t($string . 'eid.'));
$this->assertTrue(property_exists($results, 'name'), t($string . 'name.'));
- $this->assertTrue(property_exists($results, 'title'), t($string . 'title.'));
$this->assertTrue(property_exists($results, 'server'), t($string . 'server.'));
$this->assertTrue(property_exists($results, 'path' ), t($string . 'path.'));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment