Invision Power Services, Inc. * @copyright (c) Invision Power Services, Inc. * @license https://www.invisioncommunity.com/legal/standards/ * @package Invision Community * @since 10 FEB 2017 */ namespace IPS\Content\Promote; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * Twitter Promotion */ class _Twitter extends PromoteAbstract { /** * @brief Icon */ public static $icon = 'twitter'; /** * @brief Default settings */ public $defaultSettings = array( 'id' => NULL, 'owner' => NULL, 'secret' => NULL, 'token' => NULL, 'name' => NULL, 'permissions' => NULL, 'members' => NULL, 'tags' => NULL, 'tags_method' => 'fill', 'image' => NULL, 'last_sync' => 0 ); /** * @brief Twitter log in object */ protected static $twitter = NULL; /** * Twitter object * * @return Object */ protected function twitter() { if ( static::$twitter === NULL ) { static::$twitter = \IPS\Login::getHandler('Twitter'); } return static::$twitter; } /** * Get image * * @return string */ public function getPhoto() { if ( ! $this->settings['image'] or $this->settings['last_sync'] < time() - 86400 ) { $user = $this->twitter()->sendRequest( 'get', 'https://api.twitter.com/1.1/account/verify_credentials.json', array(), $this->settings['token'], $this->settings['secret'] )->decodeJson(); /* Fetch again */ $response = \IPS\Http\Url::external( $user['profile_image_url'] )->request()->get(); $extension = str_replace( 'image/', '', $response->httpHeaders['Content-Type'] ); $newFile = \IPS\File::create( 'core_Promote', 'twitter_' . $this->settings['id'] . '.' . $extension, (string) $response, NULL, FALSE, NULL, FALSE ); $this->saveSettings( array( 'image' => (string) $newFile->url, 'last_sync' => time() ) ); } return $this->settings['image']; } /** * Get name * * @return string */ public function getName() { return $this->settings['name']; } /** * Check publish permissions * * @return boolean */ public function canPostToPage() { try { $this->twitter()->sendRequest( 'get', 'https://api.twitter.com/1.1/account/verify_credentials.json', array(), $this->settings['token'], $this->settings['secret'] )->decodeJson(); return TRUE; } catch ( \IPS\Http\Request\Exception $e ) { } return FALSE; } /** * Get form elements for this share service * * @param string $text Text for the text entry * @param string $link Short or full link (short when available) * @param string $content Additional text content (usually a comment, or the item content) * * @return array of form elements */ public function form( $text, $link=null, $content=null ) { $textToActuallyUse = $text; if ( $link ) { $textToActuallyUse .= ' ' . $link; } if ( mb_strlen( $textToActuallyUse ) < 140 ) { /* Got any tags to add? */ if ( count( $this->settings['tags'] ) ) { if ( $this->settings['tags_method'] === 'trim' ) { $urlLength = mb_strlen( $link ) + 2; // spaces either side $left = 140 - $urlLength; $tagLength = 0; $tagString = ''; $useText = $text; foreach( $this->settings['tags'] as $tag ) { if ( $left > 0 ) { $tagString .= ' #' . $tag; $left -= mb_strlen( $tagString ); } } if ( $left > 20 ) { $useText = mb_substr( $text, 0, $left ); } $textToActuallyUse = $useText . ' ' . $link . ' ' . $tagString; } else { foreach( $this->settings['tags'] as $tag ) { $considerAddingThis = ' #' . $tag; if ( mb_strlen( $textToActuallyUse . $considerAddingThis ) < 140 ) { $textToActuallyUse .= $considerAddingThis; } } } } } $return = array(); if ( $this->promote and $this->promote->id ) { $textToActuallyUse = $text; $return[] = \IPS\Theme::i()->getTemplate( 'promote' )->promoteDialogTwitterDuplicate(); } $return[] = new \IPS\Helpers\Form\TextArea( 'promote_social_content_twitter', $textToActuallyUse, FALSE, array( 'maxLength' => 300, 'rows' => 3 ) ); return $return; } /** * Post to Twitter * * @param \IPS\Content\Promote $promote Promote Object * @return void */ public function post( $promote ) { $photos = $promote->imageObjects(); $mediaIds = array(); if ( count( $photos ) ) { try { $done = 0; foreach( $photos as $photo ) { /* Twitter can only have a max of 4 images */ if ( $done < 4 ) { $this->response = $this->twitter()->sendRequest( 'post', 'https://upload.twitter.com/1.1/media/upload.json', array( 'media' => $photo->contents() ), $this->settings['token'], $this->settings['secret'] )->decodeJson(); if ( isset( $this->response['media_id_string'] ) ) { $mediaIds[] = $this->response['media_id_string']; } else { \IPS\Log::log( $this->response, 'twitter' ); } $done++; } } } catch( \Exception $e ) { \IPS\Log::log( $e->getMessage(), 'twitter' ); } } try { $send = array( 'status' => $promote->text['twitter'] ); if ( count( $mediaIds ) ) { $send['media_ids'] = implode( ',', $mediaIds ); } $this->response = $this->twitter()->sendRequest( 'post', "https://api.twitter.com/1.1/statuses/update.json", $send, $this->settings['token'], $this->settings['secret'] )->decodeJson(); if ( isset( $this->response['id_str'] ) ) { return $this->response['id_str']; } else { /* Check for non critical errors we don't need to flag as complete failures */ if ( isset( $this->response['errors'] ) ) { foreach( $this->response['errors'] as $error ) { /* Status is a duplicate */ if ( $error['code'] == 187 ) { /* Fetch the original string if possible */ foreach( $promote->responses('twitter') as $response ) { if ( isset( $response['id_str'] ) ) { return $response['id_str']; } } /* No? Ok */ return 'Duplicate status'; } } } throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('twitter_publish_exception') ); } } catch ( \Exception $e ) { \IPS\Log::log( $e->getMessage(), 'twitter' ); throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('twitter_publish_exception') ); } } /** * Return the published URL * * @param array $data Data returned from a successful POST * @return \IPS\Http\Url * @throws InvalidArgumentException */ public function getUrl( $data ) { if ( $data and preg_match( '#^[0-9_]*$#', $data ) ) { return \IPS\Http\Url::external( 'https://twitter.com/' . $this->settings['id'] . '/status/' . $data ); } throw new \InvalidArgumentException(); } }