Spaces:
No application file
No application file
namespace MauticPlugin\MauticSocialBundle\Integration; | |
use MauticPlugin\MauticSocialBundle\Form\Type\TwitterType; | |
class TwitterIntegration extends SocialIntegration | |
{ | |
public const NAME = 'Twitter'; | |
public function getName(): string | |
{ | |
return self::NAME; | |
} | |
public function getPriority(): int | |
{ | |
return 5000; | |
} | |
public function getIdentifierFields(): string | |
{ | |
return 'twitter'; | |
} | |
public function getSupportedFeatures(): array | |
{ | |
return [ | |
'public_profile', | |
'public_activity', | |
'share_button', | |
'login_button', | |
]; | |
} | |
public function getAccessTokenUrl(): string | |
{ | |
return 'https://api.twitter.com/oauth/access_token'; | |
} | |
public function getAuthLoginUrl(): string | |
{ | |
$url = 'https://api.twitter.com/oauth/authorize'; | |
// Get request token | |
$requestToken = $this->getRequestToken(); | |
if (isset($requestToken['oauth_token'])) { | |
$url .= '?oauth_token='.$requestToken['oauth_token']; | |
} | |
return $url; | |
} | |
public function getRequestTokenUrl(): string | |
{ | |
return 'https://api.twitter.com/oauth/request_token'; | |
} | |
public function getAuthenticationType(): string | |
{ | |
return 'oauth1a'; | |
} | |
public function prepareRequest($url, $parameters, $method, $settings, $authType) | |
{ | |
// Prevent SSL issues | |
$settings['ssl_verifypeer'] = false; | |
if (empty($settings['authorize_session']) && 'access_token' != $authType) { | |
// Twitter requires oauth_token_secret to be part of composite key | |
if (isset($this->keys['oauth_token_secret'])) { | |
$settings['token_secret'] = $this->keys['oauth_token_secret']; | |
} | |
// Twitter also requires double encoding of parameters in building base string | |
$settings['double_encode_basestring_parameters'] = true; | |
} | |
return parent::prepareRequest($url, $parameters, $method, $settings, $authType); | |
} | |
public function getApiUrl($endpoint): string | |
{ | |
return "https://api.twitter.com/1.1/$endpoint.json"; | |
} | |
public function getUserData($identifier, &$socialCache) | |
{ | |
$accessToken = $this->getContactAccessToken($socialCache); | |
// Contact SSO | |
if (isset($accessToken['oauth_token'])) { | |
// note twitter requires params to be passed as strings | |
$data = $this->makeRequest( | |
$this->getApiUrl('account/verify_credentials'), | |
[ | |
'include_email' => 'true', | |
'include_entities' => 'false', | |
'oauth_token' => $accessToken['oauth_token'], | |
], | |
'GET', | |
['auth_type' => 'oauth1a'] | |
); | |
} | |
if (empty($data)) { | |
// Try via user lookup | |
$data = $this->makeRequest( | |
$this->getApiUrl('users/lookup'), | |
[ | |
'screen_name' => $this->cleanIdentifier($identifier), | |
'include_entities' => 'false', | |
] | |
); | |
if (isset($data[0])) { | |
$data = $data[0]; | |
} | |
} | |
if (isset($data['id'])) { | |
$socialCache['id'] = $data['id']; | |
$info = $this->matchUpData($data); | |
$info['profileHandle'] = $data['screen_name']; | |
// remove the size variant | |
$image = $data['profile_image_url_https']; | |
$image = str_replace(['_normal', '_bigger', '_mini'], '', $image); | |
$info['profileImage'] = $image; | |
$socialCache['profile'] = $info; | |
$socialCache['lastRefresh'] = new \DateTime(); | |
$this->getMauticLead($info, $this->persistNewLead, $socialCache, $identifier); | |
} | |
return $data; | |
} | |
public function getPublicActivity($identifier, &$socialCache): void | |
{ | |
if (!isset($socialCache['id'])) { | |
$this->getUserData($identifier, $socialCache); | |
if (!isset($socialCache['id'])) { | |
return; | |
} | |
} | |
$id = $socialCache['id']; | |
// due to the way Twitter filters, get more than 10 tweets | |
$data = $this->makeRequest($this->getApiUrl('/statuses/user_timeline'), [ | |
'user_id' => $id, | |
'exclude_replies' => 'true', | |
'count' => 25, | |
'trim_user' => 'true', | |
]); | |
if (!empty($data) && count($data)) { | |
$socialCache['has']['activity'] = true; | |
$socialCache['activity'] = [ | |
'tweets' => [], | |
'photos' => [], | |
'tags' => [], | |
]; | |
foreach ($data as $k => $d) { | |
if (10 == $k) { | |
break; | |
} | |
$tweet = [ | |
'tweet' => $d['text'], | |
'url' => "https://twitter.com/{$id}/status/{$d['id']}", | |
'coordinates' => $d['coordinates'], | |
'published' => $d['created_at'], | |
]; | |
$socialCache['activity']['tweets'][] = $tweet; | |
// images | |
if (isset($d['entities']['media'])) { | |
foreach ($d['entities']['media'] as $m) { | |
if ('photo' == $m['type']) { | |
$photo = [ | |
'url' => ($m['media_url_https'] ?? $m['media_url']), | |
]; | |
$socialCache['activity']['photos'][] = $photo; | |
} | |
} | |
} | |
// hastags | |
if (isset($d['entities']['hashtags'])) { | |
foreach ($d['entities']['hashtags'] as $h) { | |
if (isset($socialCache['activity']['tags'][$h['text']])) { | |
++$socialCache['activity']['tags'][$h['text']]['count']; | |
} else { | |
$socialCache['activity']['tags'][$h['text']] = [ | |
'count' => 1, | |
'url' => 'https://twitter.com/search?q=%23'.$h['text'], | |
]; | |
} | |
} | |
} | |
} | |
} | |
} | |
public function getAvailableLeadFields($settings = []): array | |
{ | |
return [ | |
'profileHandle' => ['type' => 'string'], | |
'name' => ['type' => 'string'], | |
'location' => ['type' => 'string'], | |
'description' => ['type' => 'string'], | |
'url' => ['type' => 'string'], | |
'time_zone' => ['type' => 'string'], | |
'lang' => ['type' => 'string'], | |
'email' => ['type' => 'string'], | |
]; | |
} | |
public function cleanIdentifier($identifier): string | |
{ | |
if (preg_match('#https?://twitter.com/(.*?)(/.*?|$)#i', $identifier, $match)) { | |
// extract the handle | |
$identifier = $match[1]; | |
} elseif (str_starts_with($identifier, '@')) { | |
$identifier = substr($identifier, 1); | |
} | |
return urlencode($identifier); | |
} | |
/** | |
* @param string $data | |
* @param bool $postAuthorization | |
* | |
* @return mixed | |
*/ | |
public function parseCallbackResponse($data, $postAuthorization = false) | |
{ | |
if ($postAuthorization) { | |
parse_str($data, $parsed); | |
return $parsed; | |
} | |
return json_decode($data, true); | |
} | |
public function getFormType(): string | |
{ | |
return TwitterType::class; | |
} | |
} | |