<commit_before><?php
namespace CloudWelder\PetitionsApi;

use GuzzleHttp\Client as GuzzleClient;
use CloudWelder\PetitionsApi\Exceptions\RestException;
use CloudWelder\PetitionsApi\Exceptions\InvalidApiCredentialsException;
use CloudWelder\PetitionsApi\Exceptions\OAuthException;
use GuzzleHttp;
use GuzzleHttp\Exception\ClientException;

class PetitionsApi
{
    /**
     * Basic api url
     */
    const API_ROOT = 'http://api.petitions.io/api/';
    const OAUTH_SERVER = 'http://oauth.petitions.io';    
    
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_DELETE = 'DELETE';
    
    /**
     *
     * @var string Access token for a user
     */
    protected $accessToken;
    
    /**
     *
     * @var string The client id
     */
    protected $clientId;
    
    /**
     *
     * @string Client secret for the API
     */
    protected $clientSecret;
    
    /**
     *
     * @string Url to redirect to
     */
    protected $redirectUri;
    
    /**
     *
     * @param string $clientId Your petitions.io API client id
     * @param string $clientSecret Your petitions.io API client secret
     */
    public function __construct($clientId, $clientSecret, $redirectUri) {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->redirectUri = $redirectUri;
    }
    
    /**
     *
     * Make a GET API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any query parameters
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function get($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_GET, $data);
    }
    
    /**
     *
     * Make a POST API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any data to be sent as JSON body
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function post($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_POST, $data);
    }
    
    /**
     *
     * Make a PUT API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any data to be sent as JSON body
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function put($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_PUT, $data);
    }
    
    /**
     *
     * Make a DELETE API call.
     *
     * @param string $url API endpoint (relative)
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function delete($url) {
        return $this->makeRequest($url, self::METHOD_DELETE);
    }
    
    /**
     * Set the access token to be used for any further API requests.
     *
     * @param string $token
     */
    public function withToken($token) {
        $this->accessToken = $token;
        
        return $this;
    }
    
    
    /**
     * Returns the URL users should be redirected to for them to login.
     *
     * @param string[] An array of scopes you require
     *
     * @throws InvalidApiCredentialsException
     *
     * @return string
     */
    public function getLoginUrl($scopes = []) {
        if (! $this->clientId || $this->clientId == '' ) {
            throw new InvalidApiCredentialsException('Client ID is missing');
        }
        
        if (! $this->clientSecret || $this->clientSecret == '') {
            throw new InvalidApiCredentialsException('Client Secret is missing');
        }
        
        $scopeStr = '';
        if (! empty($scopes)) {
            $scopes = array_map(function($a) {return trim($a);}, $scopes);
            $scopeStr = trim(implode(' ', $scopes));
        }
        
        $query = http_build_query([
            'client_id' => $this->clientId,
            'redirect_uri' => $this->redirectUri,
            'response_type' => 'code',
            'scope' => $scopeStr
        ]);
        
        return self::OAUTH_SERVER . "/oauth/authorize?" . $query;
    }
    
    /**
     * Retrieve/generate token from authorization code.
     *
     * @param string $authCode Authorization code from petitions.io
     *
     * @throws InvalidApiCredentialsException
     * @throws OAuthException
     *
     * @return \Cloudwelder\PetitionsApi\Token
     */
    public function getTokenFromAuthCode($authCode) {
        if (! $this->clientId || $this->clientId == '' ) {
            throw new InvalidApiCredentialsException('Client ID is missing');
        }
        
        if (! $this->clientSecret || $this->clientSecret == '') {
            throw new InvalidApiCredentialsException('Client Secret is missing');
        }
        
        $http = new GuzzleClient;
        try {
            $response = $http->post(self::OAUTH_SERVER . '/oauth/token', [
                'form_params' => [
                    'grant_type' => 'authorization_code',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'redirect_uri' => $this->redirectUri,
                    'code' => $authCode,
                ],
            ]);
        } catch (GuzzleHttp\Exception\ServerException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        }
        
        
        $petitionsResponse = new Response($response);
        
        if ($petitionsResponse->getStatusCode() == 200) {
            $data = $petitionsResponse->getResponseData();
            
            //Create a token object.
            $token = new Token($data['access_token'], $data['refresh_token'], $data['expiry_in']);
        } else {
            throw new OAuthException('Request Failed.', $response, $response->getStatusCode());
        }
        
        return $token;
    }
    
    /**
     * Refresh/re-generate token from refres token
     *
     * @param string $refreshToken Previously obtained refresh token.
     *
     * @throws OAuthException
     *
     * @return \Cloudwelder\PetitionsApi\Token
     */
    public function getTokenFromRefreshToken($refreshToken, $scopes = []) {
        $http = new GuzzleHttp\Client;
        
        $scopeStr = '';
        if (! empty($scopes)) {<commit_msg>Added support for retreving tokens using password grant (for first-party API consumers)<commit_after><?php
namespace CloudWelder\PetitionsApi;

use GuzzleHttp\Client as GuzzleClient;
use CloudWelder\PetitionsApi\Exceptions\RestException;
use CloudWelder\PetitionsApi\Exceptions\InvalidApiCredentialsException;
use CloudWelder\PetitionsApi\Exceptions\OAuthException;
use GuzzleHttp;
use GuzzleHttp\Exception\ClientException;

class PetitionsApi
{
    /**
     * Basic api url
     */
    const API_ROOT = 'http://api.petitions.io/api/';
    const OAUTH_SERVER = 'http://oauth.petitions.io';    
    
    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';
    const METHOD_PUT = 'PUT';
    const METHOD_DELETE = 'DELETE';
    
    const GRANT_AUTHCODE = 'authorization_code';
    const GRANT_PASSWORD = 'password';
    /**
     *
     * @var string Access token for a user
     */
    protected $accessToken;
    
    /**
     *
     * @var string The client id
     */
    protected $clientId;
    
    /**
     *
     * @string Client secret for the API
     */
    protected $clientSecret;
    
    /**
     *
     * @string Url to redirect to
     */
    protected $redirectUri;
    
    /**
     *
     * @param string $clientId Your petitions.io API client id
     * @param string $clientSecret Your petitions.io API client secret
     */
    public function __construct($clientId, $clientSecret, $redirectUri) {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->redirectUri = $redirectUri;
    }
    
    /**
     *
     * Make a GET API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any query parameters
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function get($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_GET, $data);
    }
    
    /**
     *
     * Make a POST API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any data to be sent as JSON body
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function post($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_POST, $data);
    }
    
    /**
     *
     * Make a PUT API call.
     *
     * @param string $url API endpoint (relative)
     * @param array $data Any data to be sent as JSON body
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function put($url, $data = []) {
        return $this->makeRequest($url, self::METHOD_PUT, $data);
    }
    
    /**
     *
     * Make a DELETE API call.
     *
     * @param string $url API endpoint (relative)
     *
     * @throws InvalidApiCredentialsException
     * @throws RestException
     *
     * @return \Cloudwelder\PetitionsApi\Response
     */
    public function delete($url) {
        return $this->makeRequest($url, self::METHOD_DELETE);
    }
    
    /**
     * Set the access token to be used for any further API requests.
     *
     * @param string $token
     */
    public function withToken($token) {
        $this->accessToken = $token;
        
        return $this;
    }
    
    
    /**
     * Returns the URL users should be redirected to for them to login.
     *
     * @param string[] An array of scopes you require
     *
     * @throws InvalidApiCredentialsException
     *
     * @return string
     */
    public function getLoginUrl($scopes = []) {
        if (! $this->clientId || $this->clientId == '' ) {
            throw new InvalidApiCredentialsException('Client ID is missing');
        }
        
        if (! $this->clientSecret || $this->clientSecret == '') {
            throw new InvalidApiCredentialsException('Client Secret is missing');
        }
        
        $scopeStr = '';
        if (! empty($scopes)) {
            $scopes = array_map(function($a) {return trim($a);}, $scopes);
            $scopeStr = trim(implode(' ', $scopes));
        }
        
        $query = http_build_query([
            'client_id' => $this->clientId,
            'redirect_uri' => $this->redirectUri,
            'response_type' => 'code',
            'scope' => $scopeStr
        ]);
        
        return self::OAUTH_SERVER . "/oauth/authorize?" . $query;
    }
    
    /**
     * Retrieve/generate token from authorization code.
     *
     * @param string $authCode Authorization code from petitions.io
     *
     * @throws InvalidApiCredentialsException
     * @throws OAuthException
     *
     * @return \Cloudwelder\PetitionsApi\Token
     */
    public function getTokenFromAuthCode($authCode) {
        if (! $this->clientId || $this->clientId == '' ) {
            throw new InvalidApiCredentialsException('Client ID is missing');
        }
        
        if (! $this->clientSecret || $this->clientSecret == '') {
            throw new InvalidApiCredentialsException('Client Secret is missing');
        }
        
        $http = new GuzzleClient;
        try {
            $response = $http->post(self::OAUTH_SERVER . '/oauth/token', [
                'form_params' => [
                    'grant_type' => self::GRANT_AUTHCODE,
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'redirect_uri' => $this->redirectUri,
                    'code' => $authCode,
                ],
            ]);
        } catch (GuzzleHttp\Exception\ServerException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        }
        
        
        $petitionsResponse = new Response($response);
        
        if ($petitionsResponse->getStatusCode() == 200) {
            $data = $petitionsResponse->getResponseData();
            
            //Create a token object.
            $token = new Token($data['access_token'], $data['refresh_token'], $data['expiry_in']);
        } else {
            throw new OAuthException('Request Failed.', $response, $response->getStatusCode());
        }
        
        return $token;
    }
    
    
    /**
     * Get access token in exchange for provding username and password.
     * 
     * @param string $username Username
     * @param string $password Password
     * @param array  $scopes Scopes
     * 
     * @throws InvalidApiCredentialsException
     * @throws OAuthException
     *
     * @return \Cloudwelder\PetitionsApi\Token
     */
    public function getTokenFromCredentials($username, $password, $scopes = []) {
        if (! $this->clientId || $this->clientId == '' ) {
            throw new InvalidApiCredentialsException('Client ID is missing');
        }
        
        if (! $this->clientSecret || $this->clientSecret == '') {
            throw new InvalidApiCredentialsException('Client Secret is missing');
        }
        
        $scopeStr = '';
        if (! empty($scopes)) {
            $scopes = array_map(function($a) {return trim($a);}, $scopes);
            $scopeStr = trim(implode(' ', $scopes));
        }
        
        $http = new GuzzleClient;
        try {
            $response = $http->post(self::OAUTH_SERVER . '/oauth/token', [
                'form_params' => [
                    'grant_type' => self::GRANT_PASSWORD,
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'username' => $username,
                    'password' => $password,
                    'scope' =>  $scopeStr
                ],
            ]);
        } catch (GuzzleHttp\Exception\ServerException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        } catch (GuzzleHttp\Exception\ClientException $e) {
            $resp = $e->getResponse();
            throw new OAuthException('oAuth Server Error', $resp, $resp->getStatusCode());
        }
        
        
        $petitionsResponse = new Response($response);
        
        if ($petitionsResponse->getStatusCode() == 200) {
            $data = $petitionsResponse->getResponseData();
            
            //Create a token object.
            $token = new Token($data['access_token'], $data['refresh_token'], $data['expiry_in']);
        } else {
            throw new OAuthException('Request Failed.', $response, $response->getStatusCode());
        }
        
        return $token;
    }
    
    /**
     * Refresh/re-generate token from refres token
     *
     * @param string $refreshToken Previously obtained refresh token.
     *
     * @throws OAuthException
     *
     * @return \Cloudwelder\PetitionsApi\Token
     */
    public function getTokenFromRefreshToken($refreshToken, $scopes = []) {
        $http = new GuzzleHttp\Client;
        
        $scopeStr = '';
        if (! empty($scopes)) {
{'fraction_non_alphanumeric': 0.12310453673330445, 'fraction_numerical': 0.000557034102865631, 'mean_word_length': 1.9855875831485588, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 102, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2089976', 'n_tokens_mistral': 4561, 'n_tokens_neox': 4508, 'n_words': 1047}