Version 4.7.6
This commit is contained in:
1 parent
8ba7d43898
commit
7b7404e741
1085 files changed
+30590
-7837
No files matched your search
@@ -1,471 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Facebook Promotion
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Facebook Promotion
|
||||
*/
|
||||
class _Facebook extends PromoteAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'facebook';
|
||||
|
||||
/**
|
||||
* @brief Default settings
|
||||
*/
|
||||
public $defaultSettings = array(
|
||||
'token' => NULL,
|
||||
'owner' => NULL,
|
||||
'page_name' => NULL, //
|
||||
'permissions' => NULL,
|
||||
'members' => NULL,
|
||||
'page' => NULL, //
|
||||
'tags' => NULL,
|
||||
'image' => NULL,
|
||||
'last_sync' => 0,
|
||||
'shareable' => array(),
|
||||
'member_token' => array(),
|
||||
);
|
||||
|
||||
/**
|
||||
* Get image
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPhoto()
|
||||
{
|
||||
if ( ! $this->settings['image'] or $this->settings['last_sync'] < time() - 86400 )
|
||||
{
|
||||
/* Fetch again */
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $this->settings['page'] . "/picture?type=large&appsecret_proof=" . static::appSecretProof( $this->settings['token'] ) )->request()->get();
|
||||
|
||||
$extension = str_replace( 'image/', '', $response->httpHeaders['Content-Type'] );
|
||||
$newFile = \IPS\File::create( 'core_Promote', 'facebook_' . $this->settings['page'] . '.' . $extension, (string) $response, NULL, FALSE, NULL, FALSE );
|
||||
|
||||
$this->saveSettings( array( 'image' => (string) $newFile->url, 'last_sync' => time() ) );
|
||||
}
|
||||
|
||||
return $this->settings['image'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
*
|
||||
* @param string|NULL $serviceId Specific page/group ID
|
||||
* @return string
|
||||
*/
|
||||
public function getName( $serviceId=NULL )
|
||||
{
|
||||
if ( $serviceId )
|
||||
{
|
||||
$realId = mb_substr( $serviceId, 2 );
|
||||
if ( mb_substr( $serviceId, 0, 2 ) == 'p_' )
|
||||
{
|
||||
return isset( $this->settings['shareable']['pages'][ $realId ]['name'] ) ? $this->settings['shareable']['pages'][ $realId ]['name'] : \IPS\Member::loggedIn()->language()->addToStack( 'promote_service_name_missing' );
|
||||
}
|
||||
else
|
||||
{
|
||||
return isset( $this->settings['shareable']['groups'][ $realId ]['name'] ) ? $this->settings['shareable']['groups'][ $realId ]['name'] : \IPS\Member::loggedIn()->language()->addToStack( 'promote_service_name_missing' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check publish permissions
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canPostToPage()
|
||||
{
|
||||
$facebook = static::getLoginHandler();
|
||||
|
||||
if ( $facebook === NULL )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$authorizedScopes = $facebook->authorizedScopes( $this->member );
|
||||
|
||||
if( $authorizedScopes === NULL )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
foreach( array( 'manage_pages', 'publish_pages' ) as $perm )
|
||||
{
|
||||
if ( ! \in_array( $perm, $authorizedScopes ) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the appSecretProof key
|
||||
*
|
||||
* @param string $token The Token
|
||||
* @return string
|
||||
*/
|
||||
protected static function appSecretProof( $token )
|
||||
{
|
||||
$facebook = static::getLoginHandler();
|
||||
return hash_hmac( 'sha256', $token, $facebook->settings['client_secret'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$shareable = array();
|
||||
$_text = '';
|
||||
|
||||
if ( $this->promote and $this->promote->id )
|
||||
{
|
||||
$_text = $text;
|
||||
|
||||
if ( isset( $this->promote->form_data['facebook'] ) AND $settings = $this->promote->form_data['facebook'] )
|
||||
{
|
||||
$shareable = $settings['shareable'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \count( $this->settings['tags'] ) )
|
||||
{
|
||||
$_text .= '#' . implode( ' #', $this->settings['tags'] );
|
||||
}
|
||||
}
|
||||
|
||||
$names = array();
|
||||
$options = array();
|
||||
if ( isset( $this->settings['shareable'] ) )
|
||||
{
|
||||
if( isset( $this->settings['shareable']['pages'] ) )
|
||||
{
|
||||
foreach( $this->settings['shareable']['pages'] as $id => $data )
|
||||
{
|
||||
$options[ 'p_' . $id ] = \IPS\Member::loggedIn()->language()->addToStack( 'promote_facebook_page_prefix', FALSE, array( 'sprintf' => array( $data['name'] ) ) );
|
||||
$names[] = $data['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if( isset( $this->settings['shareable']['groups'] ) )
|
||||
{
|
||||
foreach( $this->settings['shareable']['groups'] as $id => $data )
|
||||
{
|
||||
$options[ 'g_' . $id ] = \IPS\Member::loggedIn()->language()->addToStack( 'promote_facebook_group_prefix', FALSE, array( 'sprintf' => array( $data['name'] ) ) );
|
||||
$names[] = $data['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
new \IPS\Helpers\Form\TextArea( 'promote_social_content_facebook', $_text, FALSE, array( 'maxLength' => 2000, 'rows' => 10 ) ),
|
||||
new \IPS\Helpers\Form\CheckboxSet( 'promote_facebook_shareable', $shareable, FALSE, array( 'options' => $options ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for any extra processing
|
||||
*
|
||||
* @param array $values Values from the form isn't it though
|
||||
* @return mixed
|
||||
*/
|
||||
public function processPromoteForm( $values )
|
||||
{
|
||||
if ( isset( $values['promote_facebook_shareable'] ) )
|
||||
{
|
||||
return array( 'shareable' => $values['promote_facebook_shareable'] );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post to Facebook
|
||||
*
|
||||
* @param \IPS\core\Promote $promote Promote Object
|
||||
* @return void
|
||||
*/
|
||||
public function post( $promote )
|
||||
{
|
||||
$photos = $promote->imageObjects();
|
||||
|
||||
$settings = $promote->form_data['facebook'];
|
||||
$shareable = $this->settings['shareable'];
|
||||
$responses = array();
|
||||
|
||||
foreach( $settings['shareable'] as $id )
|
||||
{
|
||||
$feedId = mb_substr( $id, 2 );
|
||||
|
||||
if ( mb_substr( $id, 0, 2 ) == 'p_' )
|
||||
{
|
||||
$responses[ $id ][] = $this->_post( $promote, $photos, $feedId, $shareable['pages'][ $feedId ]['token'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$responses[ $id ][] = $this->_post( $promote, $photos, $feedId, isset( $this->settings['member_token']['access_token'] ) ? $this->settings['member_token']['access_token'] : $this->settings['token'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $responses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually post the post, but not post post as that would be too late
|
||||
*
|
||||
* @param \IPS\core\Promote $promote Promote Object
|
||||
* @param array $photos The photos
|
||||
* @param int $feedId The feed ID to post to. Honestly, it's not rocket science.
|
||||
* @param string $token I'll give you one guess. Does anyone actually read this?
|
||||
* @return stuff
|
||||
*/
|
||||
protected function _post( $promote, $photos, $feedId, $token=NULL )
|
||||
{
|
||||
/* Get the last 20 items to see if we have a duplicate */
|
||||
try
|
||||
{
|
||||
$items = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/feed" )->setQueryString( $this->_addToken( array(
|
||||
'limit' => 20
|
||||
), $token ) )->request()->get()->decodeJson();
|
||||
|
||||
if ( isset( $items['data'] ) )
|
||||
{
|
||||
foreach( $items['data'] as $item )
|
||||
{
|
||||
$time = new \IPS\DateTime( ( isset( $item['created_time'] ) ? $item['created_time'] : $item['updated_time' ] ) );
|
||||
$now = new \IPS\DateTime();
|
||||
|
||||
/* Only look back past the last 30 mins */
|
||||
if ( \intval( $now->diff( $time )->format('%i') ) > 30 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( preg_replace( '#\s{1,}#', " ", $promote->text['facebook'] ) == preg_replace( '#\s{1,}#', " ", $item['message'] ) )
|
||||
{
|
||||
/* Duplicate */
|
||||
return $item['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'facebook' );
|
||||
}
|
||||
|
||||
if ( ! $photos or ( \is_array( $photos ) and \count( $photos ) === 1 ) )
|
||||
{
|
||||
/* Simple message */
|
||||
try
|
||||
{
|
||||
if ( $photos )
|
||||
{
|
||||
$thePhoto = array_pop( $photos );
|
||||
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/photos" )->request()->post( $this->_addToken( array(
|
||||
'message' => $promote->text['facebook'],
|
||||
'url' => (string) $this->returnUrlWithProtocol( $thePhoto->url ),
|
||||
'link' => (string) $promote->short_link
|
||||
), $token ) )->decodeJson();
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/feed" )->request()->post( $this->_addToken( array(
|
||||
'message' => $promote->text['facebook'],
|
||||
'link' => (string) $promote->short_link
|
||||
), $token ) )->decodeJson();
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'facebook' );
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_exception') );
|
||||
}
|
||||
|
||||
if ( isset( $response['id'] ) )
|
||||
{
|
||||
return $response['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isset( $response['error'] ) )
|
||||
{
|
||||
\IPS\Log::log( $response['error']['message'], 'facebook' );
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_exception') );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have multiple photos so we first need to create an album, and then upload into that */
|
||||
try
|
||||
{
|
||||
/* The item may be a comment, which uses a language string for objectTitle - make sure that is parsed before sending */
|
||||
$title = $promote->objectTitle;
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $title );
|
||||
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $feedId . "/albums" )->request()->post( $this->_addToken( array(
|
||||
'name' => $title,
|
||||
), $token ) )->decodeJson();
|
||||
|
||||
if ( ! isset( $response['id'] ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('Could not create album');
|
||||
}
|
||||
|
||||
$newAlbumId = $response['id'];
|
||||
|
||||
foreach( $photos as $photo )
|
||||
{
|
||||
$response = \IPS\Http\Url::external( "https://graph.facebook.com/" . $newAlbumId . "/photos" )->request()->post( $this->_addToken( array(
|
||||
'message' => $promote->text['facebook'],
|
||||
'url' => (string) $this->returnUrlWithProtocol( $photo->url ),
|
||||
), $token ) )->decodeJson();
|
||||
}
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'facebook' );
|
||||
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->get('facebook_publish_exception') );
|
||||
}
|
||||
|
||||
if ( isset( $response['id'] ) )
|
||||
{
|
||||
return $response['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('facebook_publish_exception') );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds 'access_token' to query string if token defined (it is for pages, but not for groups
|
||||
*
|
||||
* @param array $values The values of the array
|
||||
* @param string|NULL $token The token obvs
|
||||
* @return array
|
||||
*/
|
||||
protected function _addToken( $values, $token )
|
||||
{
|
||||
return ( $token ) ? array_merge( $values, array( 'access_token' => $token, 'appsecret_proof' => static::appSecretProof( $token ) ) ) : $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the published URL
|
||||
*
|
||||
* @param array $data Data returned from a successful POST
|
||||
* @return \IPS\Http\Url
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getUrl( $data )
|
||||
{
|
||||
if ( \is_array( $data ) and \count( $data ) )
|
||||
{
|
||||
/* Get a random URL from the many it was shared to */
|
||||
$array = $data[ array_rand( $data ) ];
|
||||
$data = array_pop( $array );
|
||||
}
|
||||
|
||||
if ( $data and preg_match( '#^[0-9_]*$#', $data ) )
|
||||
{
|
||||
return \IPS\Http\Url::external( 'https://facebook.com/' . $data );
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this member connected to the Facebook app?
|
||||
*
|
||||
* @param \IPS\Member $member A member object
|
||||
* @return boolean
|
||||
*/
|
||||
public function isConnected( $member )
|
||||
{
|
||||
if ( \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) )
|
||||
{
|
||||
/* Standard handler */
|
||||
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
|
||||
return $facebook->canProcess( $member );
|
||||
}
|
||||
|
||||
/* Custom */
|
||||
if ( isset( $this->settings['member_token']['access_token'] ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the URL is not protocol relative
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
protected function returnUrlWithProtocol( \IPS\Http\Url $url )
|
||||
{
|
||||
if ( ! $url->data['scheme'] )
|
||||
{
|
||||
$url = $url->setScheme( ( \substr( \IPS\Settings::i()->base_url, 0, 5 ) == 'https' ) ? 'https' : 'http' );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper to Facebook log in handler with the correct settings
|
||||
*
|
||||
* @return \IPS\Login object
|
||||
*/
|
||||
public static function getLoginHandler()
|
||||
{
|
||||
$facebook = \IPS\Login\Handler::findMethod('IPS\Login\Handler\Oauth2\Facebook');
|
||||
|
||||
if ( $facebook === NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We are using the default app here */
|
||||
if ( ! \is_numeric( \IPS\Settings::i()->promote_facebook_auth ) )
|
||||
{
|
||||
$facebook->settings = json_decode( \IPS\Settings::i()->promote_facebook_auth, TRUE );
|
||||
}
|
||||
|
||||
return $facebook;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user