blob: cd0120dd1c6e3eec091c6e87c7103283adb88862 [file] [log] [blame]
#!/usr/bin/env php
<?php
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Basic class for accessing Usergrid functionality.
*
* @author Daniel Johnson <djohnson@apigee.com>
* @author Rod Simpson <rod@apigee.com>
* @since 26-Apr-2013
*/
namespace Apache\Usergrid;
require_once(dirname(__FILE__) . '/Exceptions.php');
define('AUTH_CLIENT_ID', 'CLIENT_ID');
define('AUTH_APP_USER', 'APP_USER');
define('AUTH_NONE', 'NONE');
class Client {
const SDK_VERSION = '0.1';
/**
* Usergrid endpoint
* @var string
*/
private $url = 'http://api.usergrid.com';
/**
* Organization name. Find your in the Admin Portal
* @var string
*/
private $org_name;
/**
* App name. Find your in the Admin Portal
* @var string
*/
private $app_name;
/**
* @var bool
*/
private $build_curl = FALSE;
/**
* @var bool
*/
private $use_exceptions = FALSE;
/**
* @var Callable
*/
private $log_callback = NULL;
/**
* @var int
*/
private $call_timeout = 30000;
/**
* @var Callable
*/
private $call_timeout_callback = NULL;
/**
* @var Callable
*/
private $logout_callback = NULL;
/**
* @var string
*/
private $oauth_token;
/**
* @var string
*/
private $client_id;
/**
* @var string
*/
private $client_secret;
/**
* @var string
*/
private $auth_type = AUTH_APP_USER;
/**
* Object constructor
*
* @param string $org_name
* @param string $app_name
*/
public function __construct($org_name, $app_name) {
$this->org_name = $org_name;
$this->app_name = $app_name;
}
/* Accessor functions */
/**
* Returns OAuth token if it has been set; else NULL.
*
* @return string|NULL
*/
public function get_oauth_token() {
return $this->oauth_token;
}
/**
* Sets OAuth token.
*
* @param string $token
*/
public function set_oauth_token($token) {
$this->oauth_token = $token;
}
/**
* Returns the authorization type in use.
*
* @return string
*/
public function get_auth_type() {
return $this->auth_type;
}
/**
* Sets (and validates) authorization type in use. If an invalid auth_type is
* passed, AUTH_APP_USER is assumed.
*
* @param $auth_type
* @throws UGException
*/
public function set_auth_type($auth_type) {
if ($auth_type == AUTH_APP_USER || $auth_type == AUTH_CLIENT_ID || $auth_type == AUTH_NONE) {
$this->auth_type = $auth_type;
}
else {
$this->auth_type = AUTH_APP_USER;
if ($this->use_exceptions) {
throw new UGException('Auth type is not valid');
}
}
}
/**
* Returns client_id.
*
* @return string
*/
public function get_client_id() {
return $this->client_id;
}
/**
* Sets the client ID.
*
* @param string $id
*/
public function set_client_id($id) {
$this->client_id = $id;
}
/**
* Gets the client secret.
*
* @return string
*/
public function get_client_secret() {
return $this->client_secret;
}
/**
* Sets the client secret. You should have received this information when
* you registered your UserGrid/Apache account.
*
* @param $secret
*/
public function set_client_secret($secret) {
$this->client_secret = $secret;
}
/**
* When set to TRUE, a curl command-line string will be generated. This may
* be useful when debugging.
*
* @param bool $bool
*/
public function enable_build_curl($bool = TRUE) {
$this->build_curl = (bool) $bool;
}
/**
* Returns TRUE if curl command-line building is enabled, else FALSE.
*
* @return bool
*/
public function is_build_curl_enabled() {
return $this->build_curl;
}
/**
* Enables/disables use of exceptions when errors are encountered.
*
* @param bool $bool
*/
public function enable_exceptions($bool = TRUE) {
$this->use_exceptions = (bool) $bool;
}
/**
* @return bool
*/
public function are_exceptions_enabled() {
return $this->use_exceptions;
}
/**
* Sets the callback for logging functions.
*
* @param Callable|NULL $callback
* @throws UGException
* @see write_log()
*/
public function set_log_callback($callback = NULL) {
if (!empty($callback) && !is_callable($callback)) {
if ($this->use_exceptions) {
throw new UGException('Log Callback is not callable.');
}
$this->log_callback = NULL;
}
else {
$this->log_callback = (empty($callback) ? NULL : $callback);
}
}
/**
* Sets the timeout for HTTP calls in seconds. Internally this is stored in
* milliseconds.
*
* @param int|float $seconds
*/
public function set_call_timeout($seconds = 30) {
$this->call_timeout = intval($seconds * 1000);
}
/**
* Gets timeout for HTTP calls in seconds. May return fractional parts.
*
* @return float
*/
public function get_call_timeout() {
return $this->call_timeout / 1000;
}
/**
* Sets the callback to be invoked when an HTTP call timeout occurs.
*
* @TODO Actually use/invoke this callback. Currently not implemented.
*
* @param Callable|null $callback
* @throws UGException
*/
public function set_call_timeout_callback($callback = NULL) {
if (!empty($callback) && !is_callable($callback)) {
if ($this->use_exceptions) {
throw new UGException('Call Timeout Callback is not callable.');
}
$this->call_timeout_callback = NULL;
}
else {
$this->call_timeout_callback = (empty($callback) ? NULL : $callback);
}
}
/**
* Sets the callback to be invoked upon logout.
*
* @TODO Actually use/invoke this callback. Currently not implemented.
*
* @param Callable|null $callback
* @throws UGException
*/
public function set_logout_callback($callback = NULL) {
if (!empty($callback) && !is_callable($callback)) {
if ($this->use_exceptions) {
throw new UGException('Logout Callback is not callable.');
}
$this->logout_callback = NULL;
}
else {
$this->logout_callback = (empty($callback) ? NULL : $callback);
}
}
/* End accessor functions */
/**
* If a log callback has been set, invoke it to write a given message.
*
* @param $message
*/
public function write_log($message) {
if (isset($this->log_callback)) {
call_user_func($this->log_callback, $message);
}
}
/**
* Issues a CURL request via HTTP/HTTPS and returns the response.
*
* @param Request $request
* @return Response
* @throws UG_404_NotFound
* @throws UG_403_Forbidden
* @throws UGException
* @throws UG_500_ServerError
* @throws UG_401_Unauthorized
* @throws UG_400_BadRequest
*/
public function request(Request $request) {
$method = $request->get_method();
$endpoint = $request->get_endpoint();
$body = $request->get_body();
$query_string_array = $request->get_query_string_array();
if ($this->get_auth_type() == AUTH_APP_USER) {
if ($token = $this->get_oauth_token()) {
$query_string_array['access_token'] = $token;
}
} else {
$query_string_array['client_id'] = $this->get_client_id();
$query_string_array['client_secret'] = $this->get_client_secret();
}
foreach ($query_string_array as $key => $value) {
$query_string_array[$key] = urlencode($value);
}
$query_string = http_build_query($query_string_array);
if ($request->get_management_query()) {
$url = $this->url . '/' . $endpoint;
}
else {
$url = $this->url . '/' . $this->org_name . '/' . $this->app_name . '/' . $endpoint;
}
//append params to the path
if ($query_string) {
$url .= '?' . $query_string;
}
$curl = curl_init($url);
if ($method == 'POST' || $method == 'PUT' || $method == 'DELETE') {
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
}
if ($method == 'POST' || $method == 'PUT') {
$body = json_encode($body);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Length: ' . strlen($body),
'Content-Type: application/json'
));
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, FALSE);
curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$response = curl_exec($curl);
$meta = curl_getinfo($curl);
curl_close($curl);
$response_array = @json_decode($response, TRUE);
$response_obj = new Response();
$response_obj->set_curl_meta($meta);
$response_obj->set_data($response_array);
$response_json = $response;
$response_obj->set_json($response_json);
if ($meta['http_code'] != 200) {
//there was an API error
$error_code = $response_array['error'];
$description = isset($response_array['error_description'])?$response_array['error_description']:'';
$description = isset($response_array['exception'])?$response_array['exception']:$description;
$this->write_log('Error: '.$meta['http_code'].' error:'.$description);
$response_obj->set_error(TRUE);
$response_obj->set_error_code($error_code);
$response_obj->set_error_message($description);
if ($this->use_exceptions) {
switch ($meta['http_code']) {
case 400:
throw new UG_400_BadRequest($description, $meta['http_code']);
break;
case 401:
throw new UG_401_Unauthorized($description, $meta['http_code']);
break;
case 403:
throw new UG_403_Forbidden($description, $meta['http_code']);
break;
case 404:
throw new UG_404_NotFound($description, $meta['http_code']);
break;
case 500:
throw new UG_500_ServerError($description, $meta['http_code']);
break;
default:
throw new UGException($description, $meta['http_code']);
break;
}
}
}
else {
$response_obj->set_error(FALSE);
$response_obj->set_error_message(FALSE);
}
return $response_obj;
}
/**
* Performs an HTTP GET operation
*
* @param string $endpoint
* @param array $query_string_array
* @return Response
*/
public function get($endpoint, $query_string_array) {
$request = new Request();
$request->set_method('GET');
$request->set_endpoint($endpoint);
$request->set_query_string_array($query_string_array);
$response = $this->request($request);
return $response;
}
/**
* Performs an HTTP POST operation
*
* @param string $endpoint
* @param array $query_string_array
* @param array $body
* @return Response
*/
public function post($endpoint, $query_string_array, $body) {
$request = new Request();
$request->set_method('POST');
$request->set_endpoint($endpoint);
$request->set_query_string_array($query_string_array);
$request->set_body($body);
$response = $this->request($request);
return $response;
}
/**
* Performs an HTTP PUT operation
*
* @param string $endpoint
* @param array $query_string_array
* @param array $body
* @return Response
*/
public function put($endpoint, $query_string_array, $body) {
$request = new Request();
$request->set_method('PUT');
$request->set_endpoint($endpoint);
$request->set_query_string_array($query_string_array);
$request->set_body($body);
$response = $this->request($request);
return $response;
}
/**
* Performs an HTTP DELETE operation
*
* @param string $endpoint
* @param array $query_string_array
* @return Response
*/
public function delete($endpoint, $query_string_array) {
$request = new Request();
$request->set_method('DELETE');
$request->set_endpoint($endpoint);
$request->set_query_string_array($query_string_array);
$response = $this->request($request);
return $response;
}
/**
* Creates an entity. If no error occurred, the entity may be accessed in the
* returned object's ->parsed_objects['entity'] member.
*
* @param array $entity_data
* @return \Apache\Usergrid\Entity
*/
public function create_entity($entity_data) {
$entity = new Entity($this, $entity_data);
$response = $entity->fetch();
$ok_to_save = (
($response->get_error() && ('service_resource_not_found' == $response->get_error_code() || 'no_name_specified' == $response->get_error_code() || 'null_pointer' == $response->get_error_code() ))
||
(!$response->get_error() && array_key_exists('getOnExist', $entity_data) && $entity_data['getOnExist'])
);
if ($ok_to_save) {
$entity->set($entity_data);
$response = $entity->save();
if ($response->get_error()) {
$this->write_log('Could not create entity.');
return FALSE;
}
}
elseif ($response->get_error() || array_key_exists('error', $response->get_data())) {
return FALSE;
}
return $entity;
}
/**
* Fetches and returns an entity.
*
* @param $entity_data
* @return \Apache\Usergrid\Entity|bool
*/
public function get_entity($entity_data) {
$entity = new Entity($this, $entity_data);
$response = $entity->fetch();
if ($response->get_error()) {
$this->write_log($response->get_error_message());
return FALSE;
}
return $entity;
}
/**
* Fetches and returns a collection. If the collection does not yet exist,
* it is created.
*
* @param string $type
* @param array $qs
* @return \Apache\Usergrid\Collection
*/
public function get_collection($type, $qs = array()) {
$collection = new Collection($this, $type, $qs);
return $collection;
}
/**
* Creates and returns a user-activity entity. Returns FALSE if such an
* entity could not be created.
*
* @param string $user_identifier
* @param array $user_data
* @return \Apache\Usergrid\Entity|bool
*/
public function create_user_activity($user_identifier, $user_data) {
$user_data['type'] = "users/$user_identifier/activities";
$entity = new Entity($this, $user_data);
$response = $entity->save();
return ($response->get_error() ? FALSE : $entity);
}
/**
* Attempts a login. If successful, sets the OAuth token to be used for
* subsequent calls, and returns a User entity. If unsuccessful, returns
* FALSE.
*
* @param string $username
* @param string $password
* @return \Apache\Usergrid\Entity|bool
*/
public function login($username, $password) {
$body = array(
'username' => $username,
'password' => $password,
'grant_type' => 'password'
);
$response = $this->POST('token', array(), $body);
if ($response->get_error()) {
$user = NULL;
$error = 'Error trying to log user in.';
$this->write_log($error);
if (!$response->get_error()) {
$response->set_error(TRUE);
$response->set_error_message($error);
$response->set_error_code($error);
}
}
else {
$response_data = $response->get_data();
$user = new Entity($this, $response_data['user']);
$this->set_oauth_token($response_data['access_token']);
}
return ($user && !$response->get_error() ? $user : FALSE);
}
/**
* Not yet implemented. Logs in via Facebook.
*
* @param $fb_token
*/
public function login_facebook($fb_token) {
// TODO
}
/**
* A public facing helper method for signing up users
*
* @params string $username
* @params string $password
* @params string $email
* @params string $name
* @return \Apache\Usergrid\Entity
*/
public function signup($username, $password, $email, $name) {
$data = array(
'type' => 'users',
'username' => $username,
'password' => $password,
'email' => $email,
'name' => $name
);
return $this->create_entity($data);
}
/**
* Returns current user as an entity. If no user is logged in,
* returns FALSE.
*
* @return Entity|bool
*/
public function get_logged_in_user() {
$data = array('username' => 'me', 'type' => 'users');
return $this->get_entity($data);
}
/**
* Determines if a user is logged in.
*
* @return bool
*/
public function is_logged_in() {
return !empty($this->oauth_token);
}
/**
* Logs current user out.
* @todo: Invoke logout callback.
*/
public function log_out() {
$this->oauth_token = NULL;
}
/**
* Determines if a string is a valid UUID. Note that this function will
* return FALSE if the UUID is wrapped in curly-braces, Microsoft-style.
*
* @param $uuid
* @return bool
*/
public static function is_uuid($uuid) {
static $regex = '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i';
if (empty($uuid)) {
return FALSE;
}
return (bool) preg_match($regex, $uuid);
}
// TODO: Document the following methods
public function createNewNotifierApple($name, $environment, $p12Certificate_path) {
$endpoint = "notifiers";
$data = array(
"name" => $name,
"environment" => $environment,
"p12Certificate" => $p12Certificate_path,
"provider" => "apple"
);
return $this->post($endpoint, array(), $data);
}
public function createNewNotifierAndroid($name, $apiKey) {
$endpoint = "notifiers";
$data = array(
"name" => $name,
"apiKey" => $apiKey,
"provider" => "google"
);
return $this->post($endpoint, array(), $data);
}
public function createNotification() {
return new Notification();
}
public function scheduleNotification(Notification $notification) {
$notifier_name = $notification->get_notifier_name();
$message = $notification->get_message();
$delivery_time = $notification->get_delivery_time();
$recipients_list = $notification->get_recipients_list();
$recipient_type = $notification->get_recipient_type();
//we are trying to make this (where notifierName is the name of the notifier:
// { "payloads": { notifierName: "msg" }, "deliver":timestamp }
$body = array('payloads' => array($notifier_name => $message, 'deliver' => $delivery_time));
switch ($recipient_type) {
case GROUPS:
$type = 'groups/';
break;
case USERS:
$type = 'users/';
break;
case DEVICES:
$type = 'devices/';
break;
default:
$type = 'devices/';
$recipients_list = array(';ql=');
}
//schedule notification
if (count($recipients_list) > 0) {
foreach ($recipients_list as $recipient) {
$endpoint = $type . $recipient . '/notifications';
$result = $this->post($endpoint, array(), $body);
if ($result->get_error()) {
$notification->log_error($result->get_error());
}
}
}
return $notification;
}
/**
* Gets URL of Usergrid endpoint
*
* @return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Sets Usergrid endpoint URL
*
* @param string $url
* @return bool
* @throws UGException
*/
public function setUrl($url)
{
if (filter_var($url, FILTER_VALIDATE_URL) !== false) {
$this->url = $url;
return true;
}
else {
if ($this->use_exceptions) {
throw new UGException('Invalid URL');
}
}
}
}