Tumblr: Fix #11551 and introduce NPF
authorMichael <heluecht@pirati.ca>
Thu, 6 Apr 2023 19:10:32 +0000 (19:10 +0000)
committerMichael <heluecht@pirati.ca>
Thu, 6 Apr 2023 19:10:32 +0000 (19:10 +0000)
tumblr/library/tumblroauth.php
tumblr/tumblr.php

index 418f4c8..2c95759 100644 (file)
@@ -6,6 +6,7 @@
  * The first PHP Library to support OAuth for Tumblr's REST API.  (Originally for Twitter, modified for Tumblr by Lucas)
  */
 
+use Friendica\DI;
 use Friendica\Security\OAuth1\OAuthConsumer;
 use Friendica\Security\OAuth1\OAuthRequest;
 use Friendica\Security\OAuth1\Signature\OAuthSignatureMethod_HMAC_SHA1;
@@ -17,301 +18,91 @@ use Friendica\Security\OAuth1\OAuthUtil;
  */
 class TumblrOAuth
 {
-       /* Set up the API root URL. */
-       public $host = "https://api.tumblr.com/v2/";
-       /* Set timeout default. */
-       public $timeout = 30;
-       /* Set connect timeout. */
-       public $connecttimeout = 30;
-       /* Verify SSL Cert. */
-       public $ssl_verifypeer = FALSE;
-       /* Response format. */
-       public $format = 'json';
-       /* Decode returned json data. */
-       public $decode_json = TRUE;
-       /* Set the useragent. */
-       public $useragent = 'TumblrOAuth v0.2.0-beta2';
-
        /* Contains the last HTTP status code returned. */
        public $http_code;
-       /* Contains the last API call. */
-       public $url;
-       /**
-        * Contains the last HTTP headers returned.
-        * @var array
-        */
-       public $http_header;
-       /**
-        * Contains the last HTTP request info
-        * @var string
-        */
-       public $http_info;
 
-       /** @var OAuthToken */
-       private $token;
        /** @var OAuthConsumer */
        private $consumer;
        /** @var \Friendica\Security\OAuth1\Signature\OAuthSignatureMethod_HMAC_SHA1 */
        private $sha1_method;
 
-       /**
-        * Set API URLS
-        */
-       function accessTokenURL()
-       {
-               return 'https://www.tumblr.com/oauth/access_token';
-       }
+       // API URLs
+       const accessTokenURL  = 'https://www.tumblr.com/oauth/access_token';
+       const authorizeURL    = 'https://www.tumblr.com/oauth/authorize';
+       const requestTokenURL = 'https://www.tumblr.com/oauth/request_token';
 
-       function authenticateURL()
-       {
-               return 'https://www.tumblr.com/oauth/authorize';
-       }
-
-       function authorizeURL()
-       {
-               return 'https://www.tumblr.com/oauth/authorize';
-       }
-
-       function requestTokenURL()
-       {
-               return 'https://www.tumblr.com/oauth/request_token';
-       }
-
-       function __construct($consumer_key, $consumer_secret, $oauth_token = null, $oauth_token_secret = null)
+       function __construct(string $consumer_key, string $consumer_secret)
        {
                $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
-               $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
-               if (!empty($oauth_token) && !empty($oauth_token_secret)) {
-                       $this->token = new OAuthToken($oauth_token, $oauth_token_secret);
-               } else {
-                       $this->token = null;
-               }
+               $this->consumer    = new OAuthConsumer($consumer_key, $consumer_secret);
        }
 
        /**
         * Get a request_token from Tumblr
         *
-        * @param callback $oauth_callback
+        * @param string $oauth_callback
         * @return array
         */
-       function getRequestToken($oauth_callback = null)
+       function getRequestToken(string $oauth_callback): array
        {
-               $parameters = [];
-               if (!empty($oauth_callback)) {
-                       $parameters['oauth_callback'] = $oauth_callback;
-               }
-
-               $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
-               $token = OAuthUtil::parse_parameters($request);
-               $this->token = new OAuthToken($token['oauth_token'], $token['oauth_token_secret']);
-               return $token;
+               $request = $this->oAuthRequest(self::requestTokenURL, ['oauth_callback' => $oauth_callback]);
+               return OAuthUtil::parse_parameters($request);
        }
 
        /**
         * Get the authorize URL
         *
-        * @param array $token
-        * @param bool $sign_in_with_tumblr
+        * @param string $oauth_token
         * @return string
         */
-       function getAuthorizeURL($token, $sign_in_with_tumblr = TRUE)
+       function getAuthorizeURL(string $oauth_token): string
        {
-               if (is_array($token)) {
-                       $token = $token['oauth_token'];
-               }
-
-               if (empty($sign_in_with_tumblr)) {
-                       return $this->authorizeURL() . "?oauth_token={$token}";
-               } else {
-                       return $this->authenticateURL() . "?oauth_token={$token}";
-               }
+               return self::authorizeURL . "?oauth_token={$oauth_token}";
        }
 
        /**
         * Exchange request token and secret for an access token and
         * secret, to sign API calls.
         *
-        * @param bool $oauth_verifier
+        * @param string $oauth_verifier
+        * @param string $request_token
+        * @param string $request_token_secret
         * @return array ("oauth_token" => "the-access-token",
         *                "oauth_token_secret" => "the-access-secret",
         *                "user_id" => "9436992",
         *                "screen_name" => "abraham")
         */
-       function getAccessToken($oauth_verifier = FALSE)
+       function getAccessToken(string $oauth_verifier, string $request_token, string $request_token_secret): array
        {
+               $token = new OAuthToken($request_token, $request_token_secret);
+
                $parameters = [];
                if (!empty($oauth_verifier)) {
                        $parameters['oauth_verifier'] = $oauth_verifier;
                }
 
-               $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
-               $token = OAuthUtil::parse_parameters($request);
-               $this->token = new OAuthToken($token['oauth_token'], $token['oauth_token_secret']);
-
-               return $token;
-       }
-
-       /**
-        * One time exchange of username and password for access token and secret.
-        *
-        * @param string $username
-        * @param string $password
-        * @return array ("oauth_token" => "the-access-token",
-        *                "oauth_token_secret" => "the-access-secret",
-        *                "user_id" => "9436992",
-        *                "screen_name" => "abraham",
-        *                "x_auth_expires" => "0")
-        */
-       function getXAuthToken($username, $password)
-       {
-               $parameters = [];
-               $parameters['x_auth_username'] = $username;
-               $parameters['x_auth_password'] = $password;
-               $parameters['x_auth_mode'] = 'client_auth';
-               $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
-               $token = OAuthUtil::parse_parameters($request);
-               $this->token = new OAuthToken($token['oauth_token'], $token['oauth_token_secret']);
-
-               return $token;
-       }
-
-       /**
-        * GET wrapper for oAuthRequest.
-        *
-        * @param string $url
-        * @param array $parameters
-        * @return mixed|string
-        */
-       function get($url, $parameters = [])
-       {
-               $response = $this->oAuthRequest($url, 'GET', $parameters);
-               if ($this->format === 'json' && $this->decode_json) {
-                       return json_decode($response);
-               }
-
-               return $response;
-       }
-
-       /**
-        * POST wrapper for oAuthRequest.
-        *
-        * @param string $url
-        * @param array $parameters
-        * @return mixed|string
-        */
-       function post($url, $parameters = [])
-       {
-               $response = $this->oAuthRequest($url, 'POST', $parameters);
-               if ($this->format === 'json' && $this->decode_json) {
-                       return json_decode($response);
-               }
-
-               return $response;
-       }
-
-       /**
-        * DELETE wrapper for oAuthReqeust.
-        *
-        * @param string $url
-        * @param array $parameters
-        * @return mixed|string
-        */
-       function delete($url, $parameters = [])
-       {
-               $response = $this->oAuthRequest($url, 'DELETE', $parameters);
-               if ($this->format === 'json' && $this->decode_json) {
-                       return json_decode($response);
-               }
-
-               return $response;
+               $request = $this->oAuthRequest(self::accessTokenURL, $parameters, $token);
+               return OAuthUtil::parse_parameters($request);
        }
 
        /**
         * Format and sign an OAuth / API request
         *
-        * @param string $url
-        * @param string $method
-        * @param array $parameters
-        * @return mixed|string
-        */
-       function oAuthRequest($url, $method, $parameters)
-       {
-               if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
-                       $url = "{$this->host}{$url}";
-               }
-
-               $request = OAuthRequest::from_consumer_and_token($this->consumer, $method, $url, $parameters, $this->token);
-               $request->sign_request($this->sha1_method, $this->consumer, $this->token);
-               switch ($method) {
-                       case 'GET':
-                               return $this->http($request->to_url(), 'GET');
-                       default:
-                               return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
-               }
-       }
-
-       /**
-        * Make an HTTP request
-        *
-        * @param string $url
-        * @param string $method
-        * @param mixed  $postfields
-        * @return string API results
+        * @param string     $url
+        * @param array      $parameters
+        * @param OAuthToken $token $name
+        * @return string
         */
-       function http($url, $method, $postfields = null)
+       private function oAuthRequest(string $url, array $parameters, OAuthToken $token = null): string
        {
-               $this->http_info = [];
-               $ci = curl_init();
-               /* Curl settings */
-               curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
-               curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
-               curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
-               curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
-               curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
-               curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
-               curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
-               curl_setopt($ci, CURLOPT_HEADER, FALSE);
+               $request = OAuthRequest::from_consumer_and_token($this->consumer, 'GET', $url, $parameters, $token);
+               $request->sign_request($this->sha1_method, $this->consumer, $token);
 
-               switch ($method) {
-                       case 'POST':
-                               curl_setopt($ci, CURLOPT_POST, TRUE);
-                               if (!empty($postfields)) {
-                                       curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
-                               }
-                               break;
-                       case 'DELETE':
-                               curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
-                               if (!empty($postfields)) {
-                                       $url = "{$url}?{$postfields}";
-                               }
+               $curlResult = DI::httpClient()->get($request->to_url());
+               $this->http_code = $curlResult->getReturnCode();
+               if ($curlResult->isSuccess()) {
+                       return $curlResult->getBody();
                }
-
-               curl_setopt($ci, CURLOPT_URL, $url);
-               $response = curl_exec($ci);
-               $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
-               $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
-               $this->url = $url;
-               curl_close($ci);
-
-               return $response;
-       }
-
-       /**
-        * Get the header info to store.
-        *
-        * @param resource $ch
-        * @param string $header
-        * @return int
-        */
-       function getHeader($ch, $header)
-       {
-               $i = strpos($header, ':');
-               if (!empty($i)) {
-                       $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
-                       $value = trim(substr($header, $i + 2));
-                       $this->http_header[$key] = $value;
-               }
-
-               return strlen($header);
+               return '';
        }
 }
index 41512ff..c14f02e 100644 (file)
@@ -10,6 +10,7 @@
 require_once __DIR__ . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR . 'tumblroauth.php';
 
 use Friendica\Content\Text\BBCode;
+use Friendica\Content\Text\NPF;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\Renderer;
@@ -18,7 +19,12 @@ use Friendica\Model\Item;
 use Friendica\Model\Photo;
 use Friendica\Model\Post;
 use Friendica\Model\Tag;
+use Friendica\Util\DateTimeFormat;
 use Friendica\Util\Network;
+use GuzzleHttp\Client;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Subscriber\Oauth\Oauth1;
 
 function tumblr_install()
 {
@@ -109,14 +115,14 @@ function tumblr_connect()
        $request_token = $tum_oauth->getRequestToken($callback_url);
 
        // Store the request token and Request Token Secret as out callback.php script will need this
-       $_SESSION['request_token'] = $token = $request_token['oauth_token'];
-       $_SESSION['request_token_secret'] = $request_token['oauth_token_secret'];
+       DI::session()->set('request_token', $request_token['oauth_token']);
+       DI::session()->set('request_token_secret', $request_token['oauth_token_secret']);
 
        // Check the HTTP Code.  It should be a 200 (OK), if it's anything else then something didn't work.
        switch ($tum_oauth->http_code) {
                case 200:
                        // Ask Tumblr to give us a special address to their login page
-                       $url = $tum_oauth->getAuthorizeURL($token);
+                       $url = $tum_oauth->getAuthorizeURL($request_token['oauth_token']);
 
                        // Redirect the user to the login URL given to us by Tumblr
                        header('Location: ' . $url);
@@ -143,7 +149,7 @@ function tumblr_callback()
        session_start();
 
        // Define the needed keys
-       $consumer_key = DI::config()->get('tumblr', 'consumer_key');
+       $consumer_key    = DI::config()->get('tumblr', 'consumer_key');
        $consumer_secret = DI::config()->get('tumblr', 'consumer_secret');
 
        // Once the user approves your app at Tumblr, they are sent back to this script.
@@ -153,14 +159,14 @@ function tumblr_callback()
 
        // Create instance of TumblrOAuth.
        // It'll need our Consumer Key and Secret as well as our Request Token and Secret
-       $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $_SESSION['request_token'], $_SESSION['request_token_secret']);
+       $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret);
 
        // Ok, let's get an Access Token. We'll need to pass along our oauth_verifier which was given to us in the URL.
-       $access_token = $tum_oauth->getAccessToken($_REQUEST['oauth_verifier']);
+       $access_token = $tum_oauth->getAccessToken($_REQUEST['oauth_verifier'], DI::session()->get('request_token'), DI::session()->get('request_token_secret'));
 
        // We're done with the Request Token and Secret so let's remove those.
-       unset($_SESSION['request_token']);
-       unset($_SESSION['request_token_secret']);
+       DI::session()->remove('request_token');
+       DI::session()->remove('request_token_secret');
 
        // Make sure nothing went wrong.
        if (200 == $tum_oauth->http_code) {
@@ -214,14 +220,20 @@ function tumblr_settings(array &$data)
                $consumer_key    = DI::config()->get('tumblr', 'consumer_key');
                $consumer_secret = DI::config()->get('tumblr', 'consumer_secret');
 
-               $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
-               $userinfo  = $tum_oauth->get('user/info');
+               $blogs = [];
 
-               $blogs = array_map(function ($blog) {
-                       return substr(str_replace(['http://', 'https://'], ['', ''], $blog->url), 0, -1);
-               }, $userinfo->response->user->blogs);
+               $connection = tumblr_client($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
+               if ($connection) {
+                       $userinfo = tumblr_get($connection, 'user/info');
+                       if (!empty($userinfo['success'])) {
+                               foreach ($userinfo['data']->response->user->blogs as $blog) {
+                                       $url = parse_url($blog->url, PHP_URL_HOST);
+                                       $blogs[$url] = $url;
+                               }
+                       }
+               }
 
-               $page_select = ['tumblr-page', DI::l10n()->t('Post to page:'), $page, '', $blogs];
+               $page_select = ['tumblr_page', DI::l10n()->t('Post to page:'), $page, '', $blogs];
        }
 
        $t    = Renderer::getMarkupTemplate('connector_settings.tpl', 'addon/tumblr/');
@@ -322,108 +334,194 @@ function tumblr_send(array &$b)
                return;
        }
 
+       if (tumblr_send_npf($b)) {
+               return;
+       }
+
+       $connection = tumblr_connection($b['uid']);
+       if (empty($connection)) {
+               return;
+       }
+
        $b['body'] = BBCode::removeAttachment($b['body']);
 
-       $oauth_token = DI::pConfig()->get($b['uid'], 'tumblr', 'oauth_token');
-       $oauth_token_secret = DI::pConfig()->get($b['uid'], 'tumblr', 'oauth_token_secret');
-       $page = DI::pConfig()->get($b['uid'], 'tumblr', 'page');
-       $tmbl_blog = 'blog/' . $page . '/post';
+       $title = trim($b['title']);
 
-       if ($oauth_token && $oauth_token_secret && $tmbl_blog) {
-               $tags = Tag::getByURIId($b['uri-id']);
+       $media = Post\Media::getByURIId($b['uri-id'], [Post\Media::HTML, Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]);
 
-               $tag_arr = [];
+       $photo = array_search(Post\Media::IMAGE, array_column($media, 'type'));
+       $link  = array_search(Post\Media::HTML, array_column($media, 'type'));
+       $audio = array_search(Post\Media::AUDIO, array_column($media, 'type'));
+       $video = array_search(Post\Media::VIDEO, array_column($media, 'type'));
 
-               foreach ($tags as $tag) {
-                       $tag_arr[] = $tag['name'];
-               }
+       $params = [
+               'state'  => 'published',
+               'tags'   => implode(',', array_column(Tag::getByURIId($b['uri-id']), 'name')),
+               'tweet'  => 'off',
+               'format' => 'html',
+       ];
 
-               if (count($tag_arr)) {
-                       $tags = implode(',', $tag_arr);
+       $body = BBCode::removeShareInformation($b['body']);
+       $body = Post\Media::removeFromEndOfBody($body);
+
+       if ($photo !== false) {
+               $params['type'] = 'photo';
+               $params['caption'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
+               $params['data'] = [];
+               foreach ($media as $photo) {
+                       if ($photo['type'] == Post\Media::IMAGE) {
+                               if (Network::isLocalLink($photo['url']) && ($data = Photo::getResourceData($photo['url']))) {
+                                       $photo = Photo::selectFirst([], ["`resource-id` = ? AND `scale` > ?", $data['guid'], 0]);
+                                       if (!empty($photo)) {
+                                               $params['data'][] = Photo::getImageDataForPhoto($photo);
+                                       }
+                               }
+                       }
+               }
+       } elseif ($link !== false) {
+               $params['type']        = 'link';
+               $params['title']       = $media[$link]['name'];
+               $params['url']         = $media[$link]['url'];
+               $params['description'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
+
+               if (!empty($media[$link]['preview'])) {
+                       $params['thumbnail'] = $media[$link]['preview'];
+               }
+               if (!empty($media[$link]['description'])) {
+                       $params['excerpt'] = $media[$link]['description'];
+               }
+               if (!empty($media[$link]['author-name'])) {
+                       $params['author'] = $media[$link]['author-name'];
                }
+       } elseif ($audio !== false) {
+               $params['type']         = 'audio';
+               $params['external_url'] = $media[$audio]['url'];
+               $params['caption']      = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
+       } elseif ($video !== false) {
+               $params['type']    = 'video';
+               $params['embed']   = $media[$video]['url'];
+               $params['caption'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
+       } else {
+               $params['type']  = 'text';
+               $params['title'] = $title;
+               $params['body']  = BBCode::convertForUriId($b['uri-id'], $b['body'], BBCode::CONNECTORS);
+       }
 
-               $title = trim($b['title']);
+       if (isset($params['caption']) && (trim($title) != '')) {
+               $params['caption'] = '<h1>' . $title . '</h1>' .
+                       '<p>' . $params['caption'] . '</p>';
+       }
 
-               $media = Post\Media::getByURIId($b['uri-id'], [Post\Media::HTML, Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE]);
+       $page = DI::pConfig()->get($b['uid'], 'tumblr', 'page');
 
-               $photo = array_search(Post\Media::IMAGE, array_column($media, 'type'));
-               $link  = array_search(Post\Media::HTML, array_column($media, 'type'));
-               $audio = array_search(Post\Media::AUDIO, array_column($media, 'type'));
-               $video = array_search(Post\Media::VIDEO, array_column($media, 'type'));
+       $result = tumblr_post($connection, 'blog/' . $page . '/post', $params);
 
-               $params = [
-                       'state'  => 'published',
-                       'tags'   => $tags,
-                       'tweet'  => 'off',
-                       'format' => 'html',
-               ];
+       if ($result['success']) {
+               Logger::info('success', ['blog' => $page, 'params' => $params]);
+               return true;
+       } else {
+               Logger::notice('error', ['blog' => $page, 'params' => $params, 'result' => $result['data']]);
+               return false;
+       }
+}
 
-               $body = BBCode::removeShareInformation($b['body']);
-               $body = Post\Media::removeFromEndOfBody($body);
-
-               if ($photo !== false) {
-                       $params['type'] = 'photo';
-                       $params['caption'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
-                       $params['data'] = [];
-                       foreach ($media as $photo) {
-                               if ($photo['type'] == Post\Media::IMAGE) {
-                                       if (Network::isLocalLink($photo['url']) && ($data = Photo::getResourceData($photo['url']))) {
-                                               $photo = Photo::selectFirst([], ["`resource-id` = ? AND `scale` > ?", $data['guid'], 0]);
-                                               if (!empty($photo)) {
-                                                       $params['data'][] = Photo::getImageDataForPhoto($photo);
-                                               }
-                                       }
-                               }
-                       }
-               } elseif ($link !== false) {
-                       $params['type']        = 'link';
-                       $params['title']       = $media[$link]['name'];
-                       $params['url']         = $media[$link]['url'];
-                       $params['description'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
-
-                       if (!empty($media[$link]['preview'])) {
-                               $params['thumbnail'] = $media[$link]['preview'];
-                       }
-                       if (!empty($media[$link]['description'])) {
-                               $params['excerpt'] = $media[$link]['description'];
-                       }
-                       if (!empty($media[$link]['author-name'])) {
-                               $params['author'] = $media[$link]['author-name'];
-                       }
-               } elseif ($audio !== false) {
-                       $params['type']         = 'audio';
-                       $params['external_url'] = $media[$audio]['url'];
-                       $params['caption']      = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
-               } elseif ($video !== false) {
-                       $params['type']    = 'video';
-                       $params['embed']   = $media[$video]['url'];
-                       $params['caption'] = BBCode::convertForUriId($b['uri-id'], $body, BBCode::CONNECTORS);
-               } else {
-                       $params['type']  = 'text';
-                       $params['title'] = $title;
-                       $params['body']  = BBCode::convertForUriId($b['uri-id'], $b['body'], BBCode::CONNECTORS);
-               }
+function tumblr_send_npf(array $post): bool
+{
+       $page = DI::pConfig()->get($post['uid'], 'tumblr', 'page');
 
-               if (isset($params['caption']) && (trim($title) != '')) {
-                       $params['caption'] = '<h1>' . $title . '</h1>' .
-                               '<p>' . $params['caption'] . '</p>';
-               }
+       $connection = tumblr_connection($post['uid']);
+       if (empty($connection)) {
+               Logger::notice('Missing data, post will not be send to Tumblr.', ['uid' => $post['uid'], 'page' => $page, 'id' => $post['id']]);
+               // "true" is returned, since the legacy function will fail as well.
+               return true;
+       }
+       
+       $post['body'] = Post\Media::addAttachmentsToBody($post['uri-id'], $post['body']);
+       if (!empty($post['title'])) {
+               $post['body'] = '[h1]' . $post['title'] . "[/h1]\n" . $post['body'];
+       }
 
-               $consumer_key    = DI::config()->get('tumblr', 'consumer_key');
-               $consumer_secret = DI::config()->get('tumblr', 'consumer_secret');
+       $params = [
+               'content'                => NPF::fromBBCode($post['body'], $post['uri-id']),
+               'state'                  => 'published',
+               'date'                   => DateTimeFormat::utc($post['created'], DateTimeFormat::ATOM),
+               'tags'                   => implode(',', array_column(Tag::getByURIId($post['uri-id']), 'name')),
+               'is_private'             => false,
+               'interactability_reblog' => 'everyone'
+       ];
 
-               $tum_oauth = new TumblrOAuth($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
+       $result = tumblr_post($connection, 'blog/' . $page . '/posts', $params);
+
+       if ($result['success']) {
+               Logger::info('success', ['blog' => $page, 'params' => $params]);
+               return true;
+       } else {
+               Logger::notice('error', ['blog' => $page, 'params' => $params, 'result' => $result['data']]);
+               return false;
+       }
+}
 
-               // Make an API call with the TumblrOAuth instance.
-               $x = $tum_oauth->post($tmbl_blog, $params);
-               $ret_code = $tum_oauth->http_code;
+function tumblr_connection(int $uid): GuzzleHttp\Client|null
+{
+       $oauth_token        = DI::pConfig()->get($uid, 'tumblr', 'oauth_token');
+       $oauth_token_secret = DI::pConfig()->get($uid, 'tumblr', 'oauth_token_secret');
 
-               if ($ret_code == 201) {
-                       Logger::info('success', ['blog' => $tmbl_blog, 'params' => $params]);
-               } elseif ($ret_code == 403) {
-                       Logger::notice('authentication failure', ['blog' => $tmbl_blog, 'params' => $params]);
-               } else {
-                       Logger::notice('general error', ['blog' => $tmbl_blog, 'params' => $params, 'error' => $x]);
-               }
+       $page = DI::pConfig()->get($uid, 'tumblr', 'page');
+
+       $consumer_key    = DI::config()->get('tumblr', 'consumer_key');
+       $consumer_secret = DI::config()->get('tumblr', 'consumer_secret');
+
+       if (!$consumer_key || !$consumer_secret || !$oauth_token || !$oauth_token_secret || !$page) {
+               Logger::notice('Missing data, connection is not established', ['uid' => $uid, 'page' => $page]);
+               return null;
+       }
+       return tumblr_client($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
+}
+
+function tumblr_client(string $consumer_key, string $consumer_secret, string $oauth_token, string $oauth_token_secret): GuzzleHttp\Client
+{
+       $stack = HandlerStack::create();
+
+       $middleware = new Oauth1([
+               'consumer_key'    => $consumer_key,
+               'consumer_secret' => $consumer_secret,
+               'token'           => $oauth_token,
+               'token_secret'    => $oauth_token_secret
+       ]);
+       $stack->push($middleware);
+       
+       return new Client([
+               'base_uri' => 'https://api.tumblr.com/v2/',
+               'handler' => $stack
+       ]);
+}
+
+function tumblr_get($connection, string $url)
+{
+       try {
+               $res = $connection->get($url, ['auth' => 'oauth']);
+
+               $success = true;
+               $data    = json_decode($res->getBody()->getContents());
+       } catch (RequestException $exception) {
+               $success = false;
+               Logger::notice('Request failed', ['code' => $exception->getCode(), 'message' => $exception->getMessage()]);
+               $data    = json_decode($exception->getResponse()->getBody()->getContents());
        }
+       return ['success' => $success, 'data' => $data];
 }
+
+function tumblr_post($connection, string $url, array $parameter)
+{
+       try {
+               $res = $connection->post($url, ['auth' => 'oauth', 'json' => $parameter]);
+
+               $success = true;
+               $data    = json_decode($res->getBody()->getContents());
+       } catch (RequestException $exception) {
+               $success = false;
+               Logger::notice('Post failed', ['code' => $exception->getCode(), 'message' => $exception->getMessage()]);
+               $data    = json_decode($exception->getResponse()->getBody()->getContents());
+       }
+       return ['success' => $success, 'data' => $data];
+}
\ No newline at end of file