From 87011b638edb24cea17670cfc72e10f45ed36931 Mon Sep 17 00:00:00 2001
From: Sascha Grossenbacher <saschagros@gmail.com>
Date: Mon, 16 May 2011 20:00:00 +0200
Subject: [PATCH] Issue #1158880 by Berdir: Ported services integration to services 7.x-3.x.

---
 userpoints_service.inc      |  101 ++++++++++++++++++
 userpoints_service.info     |    3 +-
 userpoints_service.module   |  239 +++++++++++++++++++++++--------------------
 userpoints_service.test     |  103 +++++++++++++++++++
 userpoints_service_test.php |   79 --------------
 5 files changed, 336 insertions(+), 189 deletions(-)
 create mode 100644 userpoints_service.inc
 create mode 100644 userpoints_service.test
 delete mode 100644 userpoints_service_test.php

diff --git a/userpoints_service.inc b/userpoints_service.inc
new file mode 100644
index 0000000..3024114
--- /dev/null
+++ b/userpoints_service.inc
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * @file
+ * Callbacks and access callbacks for userpoints services integration.
+ */
+
+/**
+ * Access callback for viewing points of users.
+ */
+function userpoints_service_view_access($uid = NULL) {
+  global $user;
+
+  return user_access('view userpoints') || ($uid && user_access('view own userpoints') && $user->uid == $uid);
+}
+
+/**
+ * Return an array of paged userpoints list.
+ *
+ * @param $page
+ *   Page number of results to return (in pages of 20).
+ *
+ * @return
+ *   An array of userpoints objects.
+ **/
+function userpoints_service_index($page, $tid, $sort, $dir) {
+  if (!in_array($sort, array('points', 'uid', 'last_updated', 'max_points'))) {
+    $sort = 'points';
+  }
+
+  if (strtoupper($dir) != 'ASC') {
+    $dir = 'DESC';
+  }
+
+  $select = db_select('userpoints', 't')
+    ->orderBy($sort, $dir);
+
+
+  if ($tid != 'all') {
+    if ($tid === NULL) {
+      $tid = userpoints_get_default_tid();
+    }
+    $select->condition('tid', $tid);
+  }
+  services_resource_build_index_query($select, $page, 'uid, points, max_points', array());
+
+  $results = $select->execute();
+
+  return services_resource_build_index_list($results, 'userpoints', 'uid');
+}
+
+/**
+ * Get the number of points of a given user.
+ */
+function userpoints_service_get($uid, $tid = NULL, $type = 'current') {
+  if (!$uid) {
+    return services_error(t('User ID parameter is required.'));
+  }
+
+  if ($tid === NULL) {
+    $tid = userpoints_get_default_tid();
+  }
+
+  if ($type == 'max') {
+    return userpoints_get_max_points($uid, $tid);
+  }
+  return userpoints_get_current_points($uid, $tid);
+}
+
+/**
+ * Add points to a user.
+ */
+function userpoints_service_add($uid, $points, $tid, $operation, $description, $entity_type, $entity_id) {
+  if (!$uid) {
+    return services_error(t('User ID parameter is required.'));
+  }
+
+  if (!$points) {
+    return services_error(t('Points parameter must be a negative or positive number.'));
+  }
+
+  $params = array(
+    'uid' => $uid,
+    'points' => $points,
+    'tid' => $tid,
+    'operation' => $operation,
+    'description' => $description,
+    'entity_type' => $entity_type,
+    'entity_id' => $entity_id,
+  );
+  $result = userpoints_userpointsapi($params);
+
+  if (!$result['status']) {
+    return services_error(t('Adding points failed: @reason' ,array('@reason' => $result['reason'])));
+  }
+
+  return (object) array(
+    'id' => $result['transaction']['txn_id'],
+    'uri' => services_resource_uri(array('userpoints_transaction', $result['transaction']['txn_id'])),
+  );
+}
\ No newline at end of file
diff --git a/userpoints_service.info b/userpoints_service.info
index 661a270..8b8c058 100644
--- a/userpoints_service.info
+++ b/userpoints_service.info
@@ -3,4 +3,5 @@ description = Exposes userpoints functionality via XML-RPC
 package = Userpoints
 dependencies[] = userpoints
 dependencies[] = services
-core = 6.x
+core = 7.x
+files[]=userpoints_service.test
diff --git a/userpoints_service.module b/userpoints_service.module
index 981985d..f1678e5 100644
--- a/userpoints_service.module
+++ b/userpoints_service.module
@@ -13,118 +13,139 @@ function userpoints_service_help($section) {
 }
 
 /**
- * Implementation of hook_service().
+ * Implementation of hook_services_resources().
  */
- 
-function userpoints_service_service() {
+function userpoints_service_services_resources() {
   return array(
-
-    array(
-      '#method'   => 'userpoints.get',
-      '#callback' => 'userpoints_service_get',
-      '#args'     => array(
-        array(
-          '#name' => 'uid',
-          '#type' => 'int',
-          '#description' => t('A valid Drupal User ID.'),
-        ), 
-        array(
-          '#name'        => 'tid',
-          '#type'        => 'int',
-          '#optional'    => TRUE,
-          '#description' => t('An optional Term ID for the category.'),
-        ), 
+    'userpoints' => array(
+      'retrieve' => array(
+        'help' => 'Retrieve the amount of points a user has',
+        'file' => array('file' => 'inc', 'module' => 'userpoints_service'),
+        'callback' => 'userpoints_service_get',
+        'access callback' => 'userpoints_service_view_access',
+        'access arguments append' => TRUE,
+        'args' => array(
+          array(
+            'name' => 'uid',
+            'type' => 'int',
+            'description' => 'The User ID for which the points should be loaded. Defaults to the .',
+            'source' => array('path' => 0),
+          ),
+          array(
+            'name' => 'tid',
+            'type' => 'all',
+            'optional' => TRUE,
+            'source' => array('param' => 'tid'),
+            'description' => t('An optional Term ID for the category.'),
+          ),
+          array(
+            'name' => 'type',
+            'type' => 'string',
+            'optional' => TRUE,
+            'source' => array('param' => 'type'),
+            'description' => t('The type of points, either max or current, to which it defaults.'),
+          ),
+        ),
       ),
-      '#return'   => 'struct',
-      '#help'     => t('Retrieves the number of points the user has.')),
-    
-    array(
-      '#method'   => 'userpoints.points',
-      '#callback' => 'userpoints_service_points',
-      '#args'     => array(
-        array(
-          '#name'        => 'uid',
-          '#type'        => 'int',
-          '#description' => t('A valid Drupal User ID.'),
-        ), 
-        array(
-          '#name'        => 'points',
-          '#type'        => 'int',
-          '#description' => t('Number of points to add/subtract.'),
-        ), 
-        array(
-          '#name'        => 'tid',
-          '#type'        => 'int',
-          '#optional'    => TRUE,
-          '#description' => t('An optional Term ID for the category.'),
-        ), 
-        array(
-          '#name'        => 'event',
-          '#type'        => 'string',
-          '#optional'    => TRUE,
-          '#description' => t('An optional event ID for this transaction.'),
-        ), 
-        array(
-          '#name'        => 'description',
-          '#type'        => 'string',
-          '#optional'    => TRUE,
-          '#description' => t('An optional description of this transaction.'),
-        ), 
+      'index' => array(
+        'help' => 'Index of all users with points',
+        'file' => array('file' => 'inc', 'module' => 'userpoints_service'),
+        'callback' => 'userpoints_service_index',
+        'access callback' => 'userpoints_service_view_access',
+        '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' => 'tid',
+            'type' => 'string',
+            'optional' => TRUE,
+            'source' => array('param' => 'tid'),
+            'description' => t('An optional Term ID for the category.'),
+          ),
+          array(
+            'name' => 'sort',
+            'type' => 'string',
+            'optional' => TRUE,
+            'default value' => 'points',
+            'source' => array('param' => 'sort'),
+            'description' => t('Sort field'),
+          ),
+          array(
+            'name' => 'dir',
+            'type' => 'string',
+            'optional' => TRUE,
+            'default value' => 'DESC',
+            'source' => array('param' => 'dir'),
+            'description' => t('Sort direction'),
+          ),
+        ),
       ),
-      '#return'   => 'struct',
-      '#help'     => t('Adds/subtracts points to a user.')),
-  );
-}
-
-/**
- * Get the number of points
- */
-function userpoints_service_get($uid, $tid = NULL) {
-  if (!$uid) {
-    return services_error(t('User ID parameter is required.'));
-  }
-
-  $points = userpoints_get_current_points($uid, $tid);
-
-  $return = new stdClass();
-  $return->points = $points;
-
-  return $return;
-}
-
-/**
- * Logout user
- */
-function userpoints_service_points($uid, $points, $tid = NULL, $event = 'userpoints service', $description = NULL) {
-  if (!$uid) {
-    return services_error(t('User ID parameter is required.'));
-  }
-
-  if (!$points) {
-    return services_error(t('Points parameter must be a negative or positive number.'));
-  }
-
-  $params = array (
-    'uid'         => $uid,
-    'points'      => $points,
-    'tid'         => $tid,
-    'event'       => $event,
-    'description' => $description,
-    'display'     => FALSE,
-    'moderate'    => FALSE,
+      'actions' => array(
+        'add' => array(
+          'help' => 'Add or subtract a given amount of points for a user',
+          'file' => array('file' => 'inc', 'module' => 'userpoints_service'),
+          'callback' => 'userpoints_service_add',
+          'access callback' => 'userpoints_admin_access',
+          'access arguments' => array('add'),
+          'args' => array(
+            array(
+              'name' => 'uid',
+              'type' => 'int',
+              'optional' => FALSE,
+              'description' => 'A valid Drupal User ID.',
+              'source' => array('data' => 'uid'),
+            ),
+            array(
+              'name' => 'points',
+              'type' => 'int',
+              'optional' => FALSE,
+              'source' => array('data' => 'points'),
+              'description' => 'Number of points to add/subtract.',
+            ),
+            array(
+              'name' => 'tid',
+              'type' => 'int',
+              'optional' => TRUE,
+              'source' => array('data' => 'tid'),
+              'description' => t('An optional Term ID for the category.'),
+            ),
+            array(
+              'name' => 'operation',
+              'type' => 'string',
+              'optional' => TRUE,
+              'source' => array('data' => 'operation'),
+              'description' => t('An operation string for this transaction.'),
+            ),
+            array(
+              'name' => 'description',
+              'type' => 'string',
+              'optional' => TRUE,
+              'source' => array('data' => 'description'),
+              'description' => t('An optional description of this transaction.'),
+            ),
+            array(
+              'name' => 'entity_type',
+              'type' => 'string',
+              'optional' => TRUE,
+              'source' => array('data' => 'entity_type'),
+              'description' => t('An optional description of this transaction.'),
+            ),
+            array(
+              'name' => 'entity_id',
+              'type' => 'int',
+              'optional' => TRUE,
+              'source' => array('data' => 'entity_id'),
+              'description' => t('An optional description of this transaction.'),
+            ),
+          ),
+        ),
+      ),
+    ),
   );
-
-  $result = userpoints_userpointsapi($params);
-
-  $return = new stdClass();
-
-  if (!$result['status']) {
-    $return->reason = $result['reason'];
-    $return->status = FALSE;
-  }
-  else {
-    $return->status = TRUE;
-  }
-
-  return $return;
 }
diff --git a/userpoints_service.test b/userpoints_service.test
new file mode 100644
index 0000000..830f95a
--- /dev/null
+++ b/userpoints_service.test
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Tests for Userpoints Services integration.
+ */
+
+// Avoid issues when the ServicesWebTestCase does not exist.
+if (!class_exists('ServicesWebTestCase')) {
+  return;
+}
+
+class UserpointsServiceTestCase extends ServicesWebTestCase {
+  /**
+   * Class variables.
+   */
+  protected $privilegedUser = NULL;
+  /**
+   * Endpoint details.
+   */
+  protected $endpoint = NULL;
+
+  /**
+   * Implements getInfo().
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Services integration'),
+      'description' => t('Tests the services resource userpoints and actions'),
+      'group' => t('Userpoints'),
+    );
+  }
+
+  /**
+   * Implementation of setUp().
+   */
+  public function setUp() {
+    parent::setUp(array('ctools', 'services', 'rest_server', 'userpoints', 'userpoints_service'));
+    // Set up endpoint.
+    $this->endpoint = $this->saveNewEndpoint();
+    // Extend endpoint with userpoints resources.
+    $this->endpoint->resources += array(
+      'userpoints' => array(
+        'alias' => '',
+        'operations' => array(
+          'retrieve' => array(
+            'enabled' => 1,
+          ),
+          'index' => array(
+            'enabled' => 1,
+          ),
+        ),
+        'actions' => array(
+          'add' => array(
+            'enabled' => 1,
+          ),
+        ),
+      ),
+    );
+
+    services_endpoint_save($this->endpoint);
+  }
+
+  /**
+   * Basic tests for granting and retreiving points through a service.
+   */
+  public function testAddRetrievePoints() {
+    // Create and log in our privileged user.
+    $this->privilegedUser = $this->drupalCreateUser(array('view userpoints', 'administer userpoints'));
+    $this->drupalLogin($this->privilegedUser);
+
+    $normal_user = $this->drupalCreateUser(array());
+
+    $total = 0;
+    for ($i = 0; $i < 3; $i++) {
+      $points = rand(-50, 50);
+      $params = array(
+        'uid' => $normal_user->uid,
+        'points' => $points,
+      );
+      $this->servicesPost($this->endpoint->path . '/userpoints/add', $params);
+      $total += $points;
+    }
+
+    $result = $this->servicesGet($this->endpoint->path . '/userpoints/' . $normal_user->uid);
+    $this->assertEqual($total, $result['body']);
+
+    // Give the admin user some points too.
+    $points = rand(-50, 50);
+    $params = array(
+      'uid' => $this->privilegedUser->uid,
+      'points' => $points,
+    );
+    $this->servicesPost($this->endpoint->path . '/userpoints/add', $params);
+
+    $result = $this->servicesGet($this->endpoint->path . '/userpoints');
+    $index = $result['body'];
+    $this->assertEqual($index[0]->points, userpoints_get_current_points($index[0]->uid));
+    $this->assertEqual($index[1]->points, userpoints_get_current_points($index[1]->uid));
+    $this->assertEqual($index[0]->max_points, userpoints_get_max_points($index[0]->uid));
+    $this->assertEqual($index[1]->max_points, userpoints_get_max_points($index[1]->uid));
+  }
+}
\ No newline at end of file
diff --git a/userpoints_service_test.php b/userpoints_service_test.php
deleted file mode 100644
index b731668..0000000
--- a/userpoints_service_test.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-
-function print_error() {
-  print_r(xmlrpc_errno());
-  print_r(xmlrpc_error_msg());
-}
-
-  if ($_SERVER['SERVER_ADDR'] && $_SERVER['REMOTE_ADDR']) {
-    print "This script should be run from the command line\n";
-    exit(1);
-  }
-
-  require_once('./includes/bootstrap.inc');
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-
-  if ($argc != 4) {
-    print "Usage: php $argv[0] uid server-URL API-key\n";
-    exit(2);
-  }
-
-  $uid = (int)$argv[1];
-  $s   = $argv[2];
-  $k   = $argv[3];
-
-  print "Querying points for user: $uid\n";
-  $result = xmlrpc($s, 'userpoints.get', $k, $uid, 0);
-  if ($result != FALSE) {
-    print "Points for user $uid = ". $result['points'] ."\n";
-  }
-  else {
-    print_error();
-  }
-
-  $points = 15;
-  print "Adding $points points for user: $uid\n";
-  $result = xmlrpc($s, 'userpoints.points', $k, $uid, $points, 0, NULL, NULL);
-  if ($result != FALSE) {
-    if ($result['status'] == TRUE) {
-      print "Success\n";
-    }
-    else {
-      print "Failed\n";
-    }
-  }
-  else {
-    print_error();
-  }
-
-  $result = xmlrpc($s, 'userpoints.get', $k, $uid, 0);
-  if ($result != FALSE) {
-    print "Points for user $uid = ". $result['points'] ."\n";
-  }
-  else {
-    print_error();
-  }
-
-  $points = -5;
-  print "Subtracting $points points for user: $uid\n";
-  $result = xmlrpc($s, 'userpoints.points', $k, $uid, $points, 0, NULL, NULL);
-  if ($result != FALSE) {
-    if ($result['status'] == TRUE) {
-      print "Success\n";
-    }
-    else {
-      print "Failed\n";
-    }
-  }
-  else {
-    print_error();
-  }
-  
-  $result = xmlrpc($s, 'userpoints.get', $k, $uid, 0);
-  if ($result != FALSE) {
-    print "Points for user $uid = ". $result['points'] ."\n";
-  }
-  else {
-    print_error();
-  }
-
-- 
1.7.4.1

