forked from friendica/friendica-addons
Merge pull request #1211 from MrPetovan/task/11022-twitter-support-delete
[twitter] Add support for unretweet and post/comment deletion
This commit is contained in:
commit
13ce3aa0a4
2 changed files with 178 additions and 49 deletions
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-10-08 22:25-0400\n"
|
||||
"POT-Creation-Date: 2021-11-23 18:33-0500\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -17,27 +17,27 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: twitter.php:224
|
||||
#: twitter.php:213
|
||||
msgid "Post to Twitter"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:269
|
||||
#: twitter.php:258
|
||||
msgid ""
|
||||
"You submitted an empty PIN, please Sign In with Twitter again to get a new "
|
||||
"one."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:329 twitter.php:333
|
||||
#: twitter.php:318 twitter.php:322
|
||||
msgid "Twitter Import/Export/Mirror"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:340
|
||||
#: twitter.php:329
|
||||
msgid ""
|
||||
"No consumer key pair for Twitter found. Please contact your site "
|
||||
"administrator."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:352
|
||||
#: twitter.php:341
|
||||
msgid ""
|
||||
"At this Friendica instance the Twitter addon was enabled but you have not "
|
||||
"yet connected your account to your Twitter account. To do so click the "
|
||||
|
@ -46,42 +46,42 @@ msgid ""
|
|||
"be posted to Twitter."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:353
|
||||
#: twitter.php:342
|
||||
msgid "Log in with Twitter"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:355
|
||||
#: twitter.php:344
|
||||
msgid "Copy the PIN from Twitter here"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:360 twitter.php:415 twitter.php:803
|
||||
#: twitter.php:349 twitter.php:404 twitter.php:924
|
||||
msgid "Save Settings"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:362 twitter.php:417
|
||||
#: twitter.php:351 twitter.php:406
|
||||
msgid "An error occured: "
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:379
|
||||
#: twitter.php:368
|
||||
msgid "Currently connected to: "
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:380 twitter.php:390
|
||||
#: twitter.php:369 twitter.php:379
|
||||
msgid "Disconnect"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:397
|
||||
#: twitter.php:386
|
||||
msgid "Allow posting to Twitter"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:397
|
||||
#: twitter.php:386
|
||||
msgid ""
|
||||
"If enabled all your <strong>public</strong> postings can be posted to the "
|
||||
"associated Twitter account. You can choose to do so by default (here) or for "
|
||||
"every posting separately in the posting options when writing the entry."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:400
|
||||
#: twitter.php:389
|
||||
msgid ""
|
||||
"<strong>Note</strong>: Due to your privacy settings (<em>Hide your profile "
|
||||
"details from unknown viewers?</em>) the link potentially included in public "
|
||||
|
@ -89,23 +89,23 @@ msgid ""
|
|||
"the visitor that the access to your profile has been restricted."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:403
|
||||
#: twitter.php:392
|
||||
msgid "Send public postings to Twitter by default"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:406
|
||||
#: twitter.php:395
|
||||
msgid "Mirror all posts from twitter that are no replies"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:409
|
||||
#: twitter.php:398
|
||||
msgid "Import the remote timeline"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:412
|
||||
#: twitter.php:401
|
||||
msgid "Automatically create contacts"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:412
|
||||
#: twitter.php:401
|
||||
msgid ""
|
||||
"This will automatically create a contact in Friendica as soon as you receive "
|
||||
"a message from an existing contact via the Twitter network. If you do not "
|
||||
|
@ -113,15 +113,25 @@ msgid ""
|
|||
"from whom you would like to see posts here."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:805
|
||||
#: twitter.php:557
|
||||
msgid ""
|
||||
"Please connect a Twitter account in your Social Network settings to import "
|
||||
"Twitter posts."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:564
|
||||
msgid "Twitter post not found."
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:926
|
||||
msgid "Consumer key"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:806
|
||||
#: twitter.php:927
|
||||
msgid "Consumer secret"
|
||||
msgstr ""
|
||||
|
||||
#: twitter.php:1002
|
||||
#: twitter.php:1123
|
||||
#, php-format
|
||||
msgid "%s on Twitter"
|
||||
msgstr ""
|
||||
|
|
|
@ -114,6 +114,7 @@ function twitter_install()
|
|||
Hook::register('prepare_body' , __FILE__, 'twitter_prepare_body');
|
||||
Hook::register('check_item_notification', __FILE__, 'twitter_check_item_notification');
|
||||
Hook::register('probe_detect' , __FILE__, 'twitter_probe_detect');
|
||||
Hook::register('item_by_link' , __FILE__, 'twitter_item_by_link');
|
||||
Hook::register('parse_link' , __FILE__, 'twitter_parse_link');
|
||||
Logger::info("installed twitter");
|
||||
}
|
||||
|
@ -411,25 +412,35 @@ function twitter_settings(App $a, &$s)
|
|||
|
||||
function twitter_hook_fork(App $a, array &$b)
|
||||
{
|
||||
DI::logger()->debug('twitter_hook_fork', $b);
|
||||
|
||||
if ($b['name'] != 'notifier_normal') {
|
||||
return;
|
||||
}
|
||||
|
||||
$post = $b['data'];
|
||||
|
||||
// Deleting and editing is not supported by the addon (deleting could, but isn't by now)
|
||||
if ($post['deleted'] || ($post['created'] !== $post['edited'])) {
|
||||
// Deletion checks are done in twitter_delete_item()
|
||||
if ($post['deleted']) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Editing is not supported by the addon
|
||||
if ($post['created'] !== $post['edited']) {
|
||||
DI::logger()->info('Editing is not supported by the addon');
|
||||
$b['execute'] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// if post comes from twitter don't send it back
|
||||
if (($post['extid'] == Protocol::TWITTER) || twitter_get_id($post['extid'])) {
|
||||
DI::logger()->info('If post comes from twitter don\'t send it back');
|
||||
$b['execute'] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (substr($post['app'], 0, 7) == 'Twitter') {
|
||||
DI::logger()->info('No Twitter app');
|
||||
$b['execute'] = false;
|
||||
return;
|
||||
}
|
||||
|
@ -444,10 +455,11 @@ function twitter_hook_fork(App $a, array &$b)
|
|||
} else {
|
||||
// Comments are never exported when we don't import the twitter timeline
|
||||
if (!strstr($post['postopts'], 'twitter') || ($post['parent'] != $post['id']) || $post['private']) {
|
||||
DI::logger()->info('Comments are never exported when we don\'t import the twitter timeline');
|
||||
$b['execute'] = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function twitter_post_local(App $a, array &$b)
|
||||
|
@ -482,7 +494,7 @@ function twitter_post_local(App $a, array &$b)
|
|||
function twitter_probe_detect(App $a, array &$hookData)
|
||||
{
|
||||
// Don't overwrite an existing result
|
||||
if ($hookData['result']) {
|
||||
if (isset($hookData['result'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -494,6 +506,13 @@ function twitter_probe_detect(App $a, array &$hookData)
|
|||
if (preg_match('=([^@]+)@(?:mobile\.)?twitter\.com$=i', $hookData['uri'], $matches)) {
|
||||
$nick = $matches[1];
|
||||
} elseif (preg_match('=^https?://(?:mobile\.)?twitter\.com/(.+)=i', $hookData['uri'], $matches)) {
|
||||
if (strpos($matches[1], '/') !== false) {
|
||||
// Status case: https://twitter.com/<nick>/status/<status id>
|
||||
// Not a contact
|
||||
$hookData['result'] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$nick = $matches[1];
|
||||
} else {
|
||||
return;
|
||||
|
@ -506,6 +525,52 @@ function twitter_probe_detect(App $a, array &$hookData)
|
|||
}
|
||||
}
|
||||
|
||||
function twitter_item_by_link(App $a, array &$hookData)
|
||||
{
|
||||
// Don't overwrite an existing result
|
||||
if (isset($hookData['item_id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Relevancy check
|
||||
if (!preg_match('#^https?://(?:mobile\.|www\.)?twitter.com/[^/]+/status/(\d+).*#', $hookData['uri'], $matches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// From now on, any early return should abort the whole chain since we've established it was a Twitter URL
|
||||
$hookData['item_id'] = false;
|
||||
|
||||
// Node-level configuration check
|
||||
if (empty(DI::config()->get('twitter', 'consumerkey')) || empty(DI::config()->get('twitter', 'consumersecret'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No anonymous import
|
||||
if (!$hookData['uid']) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
empty(DI::pConfig()->get($hookData['uid'], 'twitter', 'oauthtoken'))
|
||||
|| empty(DI::pConfig()->get($hookData['uid'], 'twitter', 'oauthsecret'))
|
||||
) {
|
||||
notice(DI::l10n()->t('Please connect a Twitter account in your Social Network settings to import Twitter posts.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$status = twitter_statuses_show($matches[1]);
|
||||
|
||||
if (empty($status->id_str)) {
|
||||
notice(DI::l10n()->t('Twitter post not found.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$item = twitter_createpost($a, $hookData['uid'], $status, [], true, false, false);
|
||||
if (!empty($item)) {
|
||||
$hookData['item_id'] = Item::insert($item);
|
||||
}
|
||||
}
|
||||
|
||||
function twitter_api_post(string $apiPath, string $pid, int $uid): ?bool
|
||||
{
|
||||
if (empty($pid)) {
|
||||
|
@ -568,9 +633,16 @@ function twitter_get_id(string $uri)
|
|||
|
||||
function twitter_post_hook(App $a, array &$b)
|
||||
{
|
||||
DI::logger()->info('twitter_post_hook', $b);
|
||||
|
||||
if ($b['deleted']) {
|
||||
twitter_delete_item($b);
|
||||
return;
|
||||
}
|
||||
|
||||
// Post to Twitter
|
||||
if (!DI::pConfig()->get($b["uid"], 'twitter', 'import')
|
||||
&& ($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))) {
|
||||
&& ($b['private'] || ($b['created'] !== $b['edited']))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -620,39 +692,21 @@ function twitter_post_hook(App $a, array &$b)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO This can't work at the moment:
|
||||
* - Posts created on Friendica and mirrored to Twitter don't have a Twitter ID
|
||||
* - Posts created on Twitter and mirrored on Friendica do not trigger the notifier hook this is part of.
|
||||
*/
|
||||
//if (($b['verb'] == Activity::POST) && $b['deleted']) {
|
||||
// twitter_api_post('statuses/destroy', twitter_get_id($thr_parent['uri']), $b['uid']);
|
||||
//}
|
||||
|
||||
if ($b['verb'] == Activity::LIKE) {
|
||||
Logger::info('Like', ['uid' => $b['uid'], 'id' => twitter_get_id($b["thr-parent"])]);
|
||||
|
||||
twitter_api_post($b['deleted'] ? 'favorites/destroy' : 'favorites/create', twitter_get_id($b["thr-parent"]), $b["uid"]);
|
||||
twitter_api_post('favorites/create', twitter_get_id($b['thr-parent']), $b['uid']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($b['verb'] == Activity::ANNOUNCE) {
|
||||
Logger::info('Retweet', ['uid' => $b['uid'], 'id' => twitter_get_id($b["thr-parent"])]);
|
||||
if ($b['deleted']) {
|
||||
/**
|
||||
* @TODO This can't work at the moment:
|
||||
* - Twitter post reshare removal doesn't seem to trigger the notifier hook this is part of
|
||||
*/
|
||||
//twitter_api_post('statuses/destroy', twitter_get_id($thr_parent['extid']), $b['uid']);
|
||||
} else {
|
||||
twitter_retweet($b["uid"], twitter_get_id($b["thr-parent"]));
|
||||
}
|
||||
|
||||
twitter_retweet($b['uid'], twitter_get_id($b['thr-parent']));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($b['deleted'] || ($b['created'] !== $b['edited'])) {
|
||||
if ($b['created'] !== $b['edited']) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -789,6 +843,71 @@ function twitter_post_hook(App $a, array &$b)
|
|||
}
|
||||
}
|
||||
|
||||
function twitter_delete_item(array $item)
|
||||
{
|
||||
if (!$item['deleted']) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($item['parent'] != $item['id']) {
|
||||
Logger::debug('Deleting comment/announce', ['item' => $item]);
|
||||
|
||||
// Looking if it's a reply to a twitter post
|
||||
if (!twitter_get_id($item['parent-uri']) &&
|
||||
!twitter_get_id($item['extid']) &&
|
||||
!twitter_get_id($item['thr-parent'])) {
|
||||
Logger::info('No twitter post', ['parent' => $item['parent']]);
|
||||
return;
|
||||
}
|
||||
|
||||
$condition = ['uri' => $item['thr-parent'], 'uid' => $item['uid']];
|
||||
$thr_parent = Post::selectFirst(['uri', 'extid', 'author-link', 'author-nick', 'author-network'], $condition);
|
||||
if (!DBA::isResult($thr_parent)) {
|
||||
Logger::warning('No parent found', ['thr-parent' => $item['thr-parent']]);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::debug('Parent found', ['parent' => $thr_parent]);
|
||||
} else {
|
||||
if (!strstr($item['extid'], 'twitter')) {
|
||||
DI::logger()->info('Not a Twitter post', ['extid' => $item['extid']]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't delete if the post doesn't belong to us.
|
||||
// This is a check for forum postings
|
||||
$self = DBA::selectFirst('contact', ['id'], ['uid' => $item['uid'], 'self' => true]);
|
||||
if ($item['contact-id'] != $self['id']) {
|
||||
DI::logger()->info('Don\'t delete if the post doesn\'t belong to the user', ['contact-id' => $item['contact-id'], 'self' => $self['id']]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @TODO Remaining caveat: Comments posted on Twitter and imported in Friendica do not trigger any Notifier task,
|
||||
* possibly because they are private to the user and don't require any remote deletion notifications sent.
|
||||
* Comments posted on Friendica and mirrored on Twitter trigger the Notifier task and the Twitter counter-part
|
||||
* will be deleted accordingly.
|
||||
*/
|
||||
if ($item['verb'] == Activity::POST) {
|
||||
Logger::info('Delete post/comment', ['uid' => $item['uid'], 'id' => twitter_get_id($item['extid'])]);
|
||||
twitter_api_post('statuses/destroy', twitter_get_id($item['extid']), $item['uid']);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($item['verb'] == Activity::LIKE) {
|
||||
Logger::info('Unlike', ['uid' => $item['uid'], 'id' => twitter_get_id($item['thr-parent'])]);
|
||||
twitter_api_post('favorites/destroy', twitter_get_id($item['thr-parent']), $item['uid']);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($item['verb'] == Activity::ANNOUNCE && !empty($thr_parent['uri'])) {
|
||||
Logger::info('Unretweet', ['uid' => $item['uid'], 'extid' => $thr_parent['uri'], 'id' => twitter_get_id($thr_parent['uri'])]);
|
||||
twitter_api_post('statuses/unretweet', twitter_get_id($thr_parent['uri']), $item['uid']);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function twitter_addon_admin_post(App $a)
|
||||
{
|
||||
$consumerkey = trim($_POST['consumerkey'] ?? '');
|
||||
|
|
Loading…
Reference in a new issue