francis94c/ci-gmail

View on GitHub
libraries/GMail.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php
declare(strict_types=1);
defined('BASEPATH') OR exit('No direct script access allowed');

class GMail {

  const AUTH_URL  = 'https://accounts.google.com/o/oauth2/auth';
  const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
  const API       = 'https://www.googleapis.com/gmail/v1/users/';
  const HTTP_CODE = 'http_code';
  const PACKAGE   = 'francis94c/ci-gmail';
  private $clientId;
  private $clientSecret;
  private $redirectUri = 'urn:ietf:wg:oauth:2.0:oob';
  private $token;
  private $userAgent = 'CodeIgniter GMail API';
  private $lastResponse;
  private $lastResponseCode;

  function __construct($params=null)
  {
    get_instance()->load->splint('francis94c/ci-gmail', '%curl');
    get_instance()->load->splint('francis94c/ci-gmail', '%base64');

    if ($params != null) $this->init($params);

    spl_autoload_register(function($name) {
      if (file_exists(APPPATH.'splints/'.self::PACKAGE."/libraries/$name.php")) {
        require(APPPATH.'splints/'.self::PACKAGE."/libraries/$name.php");
      }
    });
  }

  /**
   * [init Initialize library with cofigs. Can be called multiple times to set
   *       config items]
   * @param array $config Associative Config Array.
   */
  public function init(array $config):void {
    $this->clientId = $config['client_id'] ?? $this->clientId;
    $this->clientSecret = $config['client_secret'] ?? $this->clientSecret;
    $this->redirectUri = $config['redirect_uri'] ?? $this->redirectUri;
  }
  /**
   * [setAccessToken description]
   * @param string $token [description]
   */
  public function setAccessToken(string $token):void {
    $this->token = $token;
  }
  /**
   * [getClientId Get Client ID.]
   * @return null|string Client ID.
   */
  public function getClientId():?string {
    return $this->clientId;
  }
  /**
   * [getAuthorizeUrl Gets/composes the authorize url to direct users to so they
   *                  can give your application access to their GMail accounts
   *                  based on the given scopes.]
   * @param  string $scope        Access Scope.
   * @param  string $redirectUri  URL to redirect to after access is granted.
   * @param  string $responseType Response type. 'code' by default.
   * @param  bool   $prompt       Add the prompt=consent query to the URL.
   * @return string               Authorize URL
   */
  public function getAuthorizeUrl(string $scope, string $redirectUri=null,
  string $responseType='code', string $accessType='offline', bool $prompt=false):string
  {
    $redirectUri = $redirectUri ?? $this->redirectUri;
    if ($scope == null) throw new Exception("GMail scope cannot be null");
    $params = [
      'client_id'     => $this->clientId,
      'redirect_uri'  => $redirectUri,
      'scope'         => $scope,
      'response_type' => $responseType,
      'access_type'   => $accessType
    ];
    if ($prompt) $params['prompt'] = 'consent';
    return self::AUTH_URL . build_url_query($params, false);
  }
  /**
   * [getToken description]
   * @param  string $code [description]
   * @return [type]       [description]
   */
  public function getToken(string $code, string $redirectUri=null):?object
  {
    $redirectUri = $redirectUri ?? $this->redirectUri;
    $ch = curl_init(self::TOKEN_URL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    if (ENVIRONMENT == 'development') {
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    }
    $body = http_build_query([
      'code'          => $code,
      'client_id'     => $this->clientId,
      'client_secret' => $this->clientSecret,
      'redirect_uri'  => $redirectUri,
      'grant_type'    => 'authorization_code'
    ]);
    $header = [
      'Content-Type: application/x-www-form-urlencoded',
      'Content-Length: ' . strlen($body)
    ];
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
    // Request Method and Body.
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    $response = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) return $this->process_response($code, $response);
    return null;
  }
  /**
   * [refreshAccessToken description]
   * @param  string $refreshToken [description]
   * @return [type]               [description]
   */
  public function refreshAccessToken(string $refreshToken):?object
  {
    $ch = curl_init(self::TOKEN_URL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLINFO_HEADER_OUT, true);
    if (ENVIRONMENT == 'development') {
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    }
    $body = http_build_query([
      'refresh_token' => $refreshToken,
      'client_id'     => $this->clientId,
      'client_secret' => $this->clientSecret,
      'grant_type'    => 'refresh_token'
    ]);
    $header = [
      'Content-Type: application/x-www-form-urlencoded',
      'Content-Length: ' . strlen($body)
    ];
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
    // Request Method and Body.
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    // Exec.
    $response = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) return $this->process_response($code, $response);
    return null;
  }
  /**
   * [getProfile Get user's profile
   * see https://developers.google.com/gmail/api/v1/reference/users/getProfile]
   * @param  string $user [description]
   * @return [type]       [description]
   */
  public function getProfile(string $user='me'):?object
  {
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
      self::API . "$user/profile",
      ["Authorization: Bearer $this->token"]
    );
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) return $this->process_response($code, $response);
    return null;
  }

  /**
   * [watch Causes push notifications to be sent on events which occur in the
   * user's mailbox. Requires Google Cloud PubSub.
   * see https://developers.google.com/gmail/api/v1/reference/users/watch]
   * @param  string $topic             Topic to push events to.
   * @param  mixed  $labelIds          Narrow down labels in the mailbox, whose
   *                                   mailbox event, are being listened to.
   *                                   events are to be listened to.
   * @param  string $userId            The ID/Email address of the user.
   * @param  string $labelFilterAction [description]
   * @return [type]                    [description]
   */
  public function watch(string $topic, $labelIds=null, string $userId='me',
  string $labelFilterAction='include'):?object
  {
    $body = [
      'topicName'         => $topic,
      'labelFilterAction' => $labelFilterAction
    ];

    if ($labelIds != null) {
      if (is_scalar($labelIds)) {
        $body['labelIds'] = [$labelIds];
      } elseif (is_array($labelIds)) {
        $body['labelIds'] = $labelIds;
      }
    }

    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
      self::API . "$userId/watch",
      ["Authorization: Bearer $this->token"],
      $body
    );
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) return $this->process_response($code, $response);
    return null;
  }

  /**
   * [endWatch stop watch operations on given email ID]
   * @date   2019-11-20
   * @param  string     $userId ID or Email Address of the user.
   * @return bool               [description]
   */
  public function endWatch(string $userId='me'):bool
  {
    list($code, $response) = (new GMailCURL(GMailCURL::POST))(
      self::API . "$userId/stop",
      ["Authorization: Bearer $this->token"]
    );
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) return $code == 204;
    return false;
  }

  /**
   * [getLabels description]
   * @date   2019-11-20
   * @param  string     $userID [description]
   * @return null|array         [description]
   */
  public function getLabels(string $userId='me'):?array
  {
    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
      self::API . "$userId/labels",
      ["Authorization: Bearer $this->token"]
    );
    $this->lastResponse = $response;
    $this->lastResponseCode = $code;
    if ($response !== false) {
      return json_decode($response)->labels;
    }
    return null;
  }
  /**
   * [getMessages description]
   * @date   2019-11-21
   * @param  string     $userId           [description]
   * @param  [type]     $labelIds         [description]
   * @param  [type]     $q                [description]
   * @param  [type]     $maxMessages      [description]
   * @param  [type]     $pageToken        [description]
   * @param  boolean    $includeSpamTrash [description]
   * @param  [type]     $truncateAfter    [description]
   * @return [type]                       [description]
   */
  public function getMessages(string $userId='me', array $labelIds=null,
  string $q=null, int $maxMessages=null, string $pageToken=null, bool $includeSpamTrash=false,
  $truncateAfter=null):?object
  {
    $query = [];

    if ($labelIds) $query['labelIds'] = $labelIds;
    if ($includeSpamTrash) $query['includeSpamTrash'] = $includeSpamTrash;
    if ($q) $query['q'] = $q;
    if ($pageToken) $query['pageToken'] = $pageToken;
    if ($maxMessages) $query['maxResults'] = $maxMessages;

    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
      self::API . "$userId/messages" . build_url_query($query),
      ["Authorization: Bearer $this->token"]
    );

    $this->lastResponse = $response;
    $this->lastResponseCode = $code;

    if ($response !== false) {
      if ($truncateAfter != null && $code == 200) {
        $response = json_decode($response);
        if ($response->messages) {
          $response->messages = array_filter($response->messages, function ($e) use ($truncateAfter) {
            return strcmp($truncateAfter, $e->id) < 0;
          });
        }
        $response->{self::HTTP_CODE} = $code;
        return $response;
      }

      return $this->process_response($code, $response);
    }

    return null;
  }

  /**
   * [getLastMessageId description]
   * @date   2020-03-08
   * @return string|null [description]
   */
  public function getLastMessageId():?string
  {
    $messages = $this->getMessages();
    return $messages->messages[0]->id ?? null;
  }

  /**
   * [getMessage description]
   * @date   2019-11-21
   * @param  string       $userId          [description]
   * @param  string       $messageId       [description]
   * @param  string       $format          [description]
   * @param  [type]       $metadataHeaders [description]
   * @return Message|null                  [description]
   */
  public function getMessage(string $userId='me', string $messageId,
  string $format='full', array $metadataHeaders=null):?Message
  {
    $query = [];

    if ($format != 'full' && $format != null) $query['format'] = $format;
    if ($metadataHeaders != null) $query['metadataHeaders'] = $metadataHeaders;

    list($code, $response) = (new GMailCURL(GMailCURL::GET))(
      self::API . "$userId/messages/$messageId?" . http_build_query($query),
      ["Authorization: Bearer $this->token"]
    );

    $this->lastResponse = $response;
    $this->lastResponseCode = $code;

    if ($response !== false) return new Message($response);

    return null;
  }

  /**
   * [getLastResponse description]
   * @date   2020-03-07
   * @return string     [description]
   */
  public function getLastResponse():string
  {
    return $this->lastResponse;
  }

  /**
   * [getLastResponseCode description]
   * @date   2020-03-07
   * @return int        [description]
   */
  public function getLastResponseCode():int
  {
    return $this->lastResponseCode;
  }

  /**
   * [process_response description]
   * @param  int    $code     [description]
   * @param  string $response [description]
   * @return [type]           [description]
   */
  private function process_response(int $code, string $response):?object {
    $response = json_decode($response);
    $response->{self::HTTP_CODE} = $code;
    return $response;
  }
}