Profile update and some more is now added
This commit is contained in:
parent
761bdafa34
commit
5456ef0185
2 changed files with 167 additions and 46 deletions
|
@ -44,27 +44,25 @@ use Friendica\Core\Config;
|
||||||
* To-do:
|
* To-do:
|
||||||
*
|
*
|
||||||
* Receiver:
|
* Receiver:
|
||||||
* - Update Note
|
* - Update (Image, Video, Article, Note)
|
||||||
* - Delete Note
|
+ - Event
|
||||||
* - Delete Person
|
|
||||||
* - Undo Announce
|
* - Undo Announce
|
||||||
* - Reject Follow
|
*
|
||||||
* - Undo Accept
|
* Check what this is meant to do:
|
||||||
* - Undo Follow
|
|
||||||
* - Add
|
* - Add
|
||||||
* - Create Image
|
|
||||||
* - Create Video
|
|
||||||
* - Event
|
|
||||||
* - Remove
|
|
||||||
* - Block
|
* - Block
|
||||||
* - Flag
|
* - Flag
|
||||||
|
* - Remove
|
||||||
|
* - Undo Block
|
||||||
|
* - Undo Accept (Problem: This could invert a contact accept or an event accept)
|
||||||
*
|
*
|
||||||
* Transmitter:
|
* Transmitter:
|
||||||
|
* - Delete (Application, Group, Organization, Person, Service)
|
||||||
|
* - Event
|
||||||
|
*
|
||||||
|
* Complicated:
|
||||||
* - Announce
|
* - Announce
|
||||||
* - Undo Announce
|
* - Undo Announce
|
||||||
* - Update Person
|
|
||||||
* - Reject Follow
|
|
||||||
* - Event
|
|
||||||
*
|
*
|
||||||
* General:
|
* General:
|
||||||
* - Attachments
|
* - Attachments
|
||||||
|
@ -81,7 +79,9 @@ class ActivityPub
|
||||||
'diaspora' => 'https://diasporafoundation.org/ns/',
|
'diaspora' => 'https://diasporafoundation.org/ns/',
|
||||||
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
|
||||||
'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag']];
|
'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag']];
|
||||||
|
const ACCOUNT_TYPES = ['Person', 'Organization', 'Service', 'Group', 'Application'];
|
||||||
|
const CONTENT_TYPES = ['Note', 'Article', 'Video', 'Image'];
|
||||||
|
const ACTIVITY_TYPES = ['Like', 'Dislike', 'Accept', 'Reject', 'TentativeAccept'];
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the web request is done for the AP protocol
|
* @brief Checks if the web request is done for the AP protocol
|
||||||
*
|
*
|
||||||
|
@ -243,7 +243,6 @@ class ActivityPub
|
||||||
*/
|
*/
|
||||||
public static function profile($uid)
|
public static function profile($uid)
|
||||||
{
|
{
|
||||||
$accounttype = ['Person', 'Organization', 'Service', 'Group', 'Application'];
|
|
||||||
$condition = ['uid' => $uid, 'blocked' => false, 'account_expired' => false,
|
$condition = ['uid' => $uid, 'blocked' => false, 'account_expired' => false,
|
||||||
'account_removed' => false, 'verified' => true];
|
'account_removed' => false, 'verified' => true];
|
||||||
$fields = ['guid', 'nickname', 'pubkey', 'account-type', 'page-flags'];
|
$fields = ['guid', 'nickname', 'pubkey', 'account-type', 'page-flags'];
|
||||||
|
@ -267,7 +266,7 @@ class ActivityPub
|
||||||
$data = ['@context' => self::CONTEXT];
|
$data = ['@context' => self::CONTEXT];
|
||||||
$data['id'] = $contact['url'];
|
$data['id'] = $contact['url'];
|
||||||
$data['diaspora:guid'] = $user['guid'];
|
$data['diaspora:guid'] = $user['guid'];
|
||||||
$data['type'] = $accounttype[$user['account-type']];
|
$data['type'] = self::ACCOUNT_TYPES[$user['account-type']];
|
||||||
$data['following'] = System::baseUrl() . '/following/' . $user['nickname'];
|
$data['following'] = System::baseUrl() . '/following/' . $user['nickname'];
|
||||||
$data['followers'] = System::baseUrl() . '/followers/' . $user['nickname'];
|
$data['followers'] = System::baseUrl() . '/followers/' . $user['nickname'];
|
||||||
$data['inbox'] = System::baseUrl() . '/inbox/' . $user['nickname'];
|
$data['inbox'] = System::baseUrl() . '/inbox/' . $user['nickname'];
|
||||||
|
@ -431,6 +430,29 @@ class ActivityPub
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fetches a list of inboxes of followers of a given user
|
||||||
|
*
|
||||||
|
* @param integer $uid User ID
|
||||||
|
*
|
||||||
|
* @return array of follower inboxes
|
||||||
|
*/
|
||||||
|
private static function fetchTargetInboxesforUser($uid)
|
||||||
|
{
|
||||||
|
$inboxes = [];
|
||||||
|
|
||||||
|
$contacts = DBA::select('contact', ['notify', 'batch'], ['uid' => $uid,
|
||||||
|
'rel' => [Contact::FOLLOWER, Contact::FRIEND], 'network' => Protocol::ACTIVITYPUB,
|
||||||
|
'archive' => false, 'pending' => false]);
|
||||||
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
|
$contact = defaults($contact, 'batch', $contact['notify']);
|
||||||
|
$inboxes[$contact] = $contact;
|
||||||
|
}
|
||||||
|
DBA::close($contacts);
|
||||||
|
|
||||||
|
return $inboxes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fetches an array of inboxes for the given item and user
|
* @brief Fetches an array of inboxes for the given item and user
|
||||||
*
|
*
|
||||||
|
@ -461,14 +483,7 @@ class ActivityPub
|
||||||
|
|
||||||
foreach ($permissions[$element] as $receiver) {
|
foreach ($permissions[$element] as $receiver) {
|
||||||
if ($receiver == $item_profile['followers']) {
|
if ($receiver == $item_profile['followers']) {
|
||||||
$contacts = DBA::select('contact', ['notify', 'batch'], ['uid' => $uid,
|
$inboxes = self::fetchTargetInboxesforUser($uid);
|
||||||
'rel' => [Contact::FOLLOWER, Contact::FRIEND], 'network' => Protocol::ACTIVITYPUB,
|
|
||||||
'archive' => false, 'pending' => false]);
|
|
||||||
while ($contact = DBA::fetch($contacts)) {
|
|
||||||
$contact = defaults($contact, 'batch', $contact['notify']);
|
|
||||||
$inboxes[$contact] = $contact;
|
|
||||||
}
|
|
||||||
DBA::close($contacts);
|
|
||||||
} else {
|
} else {
|
||||||
$profile = APContact::getByURL($receiver);
|
$profile = APContact::getByURL($receiver);
|
||||||
if (!empty($profile)) {
|
if (!empty($profile)) {
|
||||||
|
@ -716,6 +731,36 @@ class ActivityPub
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmits a profile change to the followers
|
||||||
|
*
|
||||||
|
* @param integer $uid User ID
|
||||||
|
*/
|
||||||
|
public static function transmitProfileUpdate($uid)
|
||||||
|
{
|
||||||
|
$owner = User::getOwnerDataById($uid);
|
||||||
|
$profile = APContact::getByURL($owner['url']);
|
||||||
|
|
||||||
|
$data = ['@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
|
'id' => System::baseUrl() . '/activity/' . System::createGUID(),
|
||||||
|
'type' => 'Update',
|
||||||
|
'actor' => $owner['url'],
|
||||||
|
'object' => self::profile($uid),
|
||||||
|
'published' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
|
||||||
|
'to' => [$profile['followers']],
|
||||||
|
'cc' => []];
|
||||||
|
|
||||||
|
logger('Sending profile update to followers for user ' . $uid, LOGGER_DEBUG);
|
||||||
|
|
||||||
|
$signed = LDSignature::sign($data, $owner);
|
||||||
|
|
||||||
|
$inboxes = self::fetchTargetInboxesforUser($uid);
|
||||||
|
|
||||||
|
foreach ($inboxes as $inbox) {
|
||||||
|
logger('Deliver profile update for user ' . $uid . ' to ' . $inbox .' via ActivityPub', LOGGER_DEBUG);
|
||||||
|
HTTPSignature::transmit($signed, $inbox, $uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Transmits a given activity to a target
|
* @brief Transmits a given activity to a target
|
||||||
*
|
*
|
||||||
|
@ -1088,12 +1133,19 @@ class ActivityPub
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Update':
|
case 'Update':
|
||||||
if (in_array($object_data['object_type'], ['Person', 'Organization', 'Service', 'Group', 'Application'])) {
|
if (in_array($object_data['object_type'], self::CONTENT_TYPES)) {
|
||||||
|
/// @todo
|
||||||
|
} elseif (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) {
|
||||||
self::updatePerson($object_data, $body);
|
self::updatePerson($object_data, $body);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Delete':
|
case 'Delete':
|
||||||
|
if ($object_data['object_type'] == 'Tombstone') {
|
||||||
|
self::deleteItem($object_data, $body);
|
||||||
|
} elseif (in_array($object_data['object_type'], self::ACCOUNT_TYPES)) {
|
||||||
|
self::deletePerson($object_data, $body);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Follow':
|
case 'Follow':
|
||||||
|
@ -1106,10 +1158,16 @@ class ActivityPub
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'Reject':
|
||||||
|
if ($object_data['object_type'] == 'Follow') {
|
||||||
|
self::rejectFollowUser($object_data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'Undo':
|
case 'Undo':
|
||||||
if ($object_data['object_type'] == 'Follow') {
|
if ($object_data['object_type'] == 'Follow') {
|
||||||
self::undoFollowUser($object_data);
|
self::undoFollowUser($object_data);
|
||||||
} elseif (in_array($object_data['object_type'], ['Like', 'Dislike', 'Accept', 'Reject', 'TentativeAccept'])) {
|
} elseif (in_array($object_data['object_type'], self::ACTIVITY_TYPES)) {
|
||||||
self::undoActivity($object_data);
|
self::undoActivity($object_data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1324,26 +1382,18 @@ class ActivityPub
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($data['type']) {
|
if (in_array($data['type'], self::CONTENT_TYPES)) {
|
||||||
case 'Note':
|
return self::processObject($data);
|
||||||
case 'Article':
|
|
||||||
case 'Video':
|
|
||||||
return self::processObject($data);
|
|
||||||
|
|
||||||
case 'Announce':
|
|
||||||
if (empty($data['object'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return self::fetchObject($data['object']);
|
|
||||||
|
|
||||||
case 'Person':
|
|
||||||
case 'Tombstone':
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
logger('Unknown object type: ' . $data['type'], LOGGER_DEBUG);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($data['type'] == 'Announce') {
|
||||||
|
if (empty($data['object'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return self::fetchObject($data['object']);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger('Unhandled object type: ' . $data['type'], LOGGER_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1548,6 +1598,20 @@ class ActivityPub
|
||||||
self::postItem($activity, $item, $body);
|
self::postItem($activity, $item, $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete items
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
* @param $body
|
||||||
|
*/
|
||||||
|
private static function deleteItem($activity)
|
||||||
|
{
|
||||||
|
$owner = Contact::getIdForURL($activity['owner']);
|
||||||
|
$object = JsonLD::fetchElement($activity, 'object', 'id');
|
||||||
|
logger('Deleting item ' . $object . ' from ' . $owner, LOGGER_DEBUG);
|
||||||
|
Item::delete(['uri' => $object, 'owner-id' => $owner]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
|
@ -1710,6 +1774,32 @@ class ActivityPub
|
||||||
APContact::getByURL($activity['object']['id'], true);
|
APContact::getByURL($activity['object']['id'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete the given profile
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
*/
|
||||||
|
private static function deletePerson($activity)
|
||||||
|
{
|
||||||
|
if (empty($activity['object']['id']) || empty($activity['object']['actor'])) {
|
||||||
|
logger('Empty object id or actor.', LOGGER_DEBUG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity['object']['id'] != $activity['object']['actor']) {
|
||||||
|
logger('Object id does not match actor.', LOGGER_DEBUG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contacts = DBA::select('contact', ['id'], ['nurl' => normalise_link($activity['object']['id'])]);
|
||||||
|
while ($contact = DBA::fetch($contacts)) {
|
||||||
|
Contact::remove($contact["id"]);
|
||||||
|
}
|
||||||
|
DBA::close($contacts);
|
||||||
|
|
||||||
|
logger('Deleted contact ' . $activity['object']['id'], LOGGER_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Accept a follow request
|
* @brief Accept a follow request
|
||||||
*
|
*
|
||||||
|
@ -1743,6 +1833,35 @@ class ActivityPub
|
||||||
logger('Accept contact request from contact ' . $cid . ' for user ' . $uid, LOGGER_DEBUG);
|
logger('Accept contact request from contact ' . $cid . ' for user ' . $uid, LOGGER_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reject a follow request
|
||||||
|
*
|
||||||
|
* @param array $activity
|
||||||
|
*/
|
||||||
|
private static function rejectFollowUser($activity)
|
||||||
|
{
|
||||||
|
$actor = JsonLD::fetchElement($activity, 'object', 'actor');
|
||||||
|
$uid = User::getIdForURL($actor);
|
||||||
|
if (empty($uid)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner = User::getOwnerDataById($uid);
|
||||||
|
|
||||||
|
$cid = Contact::getIdForURL($activity['owner'], $uid);
|
||||||
|
if (empty($cid)) {
|
||||||
|
logger('No contact found for ' . $activity['owner'], LOGGER_DEBUG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBA::exists('contact', ['id' => $cid, 'rel' => Contact::SHARING, 'pending' => true])) {
|
||||||
|
Contact::remove($cid);
|
||||||
|
logger('Rejected contact request from contact ' . $cid . ' for user ' . $uid . ' - contact had been removed.', LOGGER_DEBUG);
|
||||||
|
} else {
|
||||||
|
logger('Rejected contact request from contact ' . $cid . ' for user ' . $uid . '.', LOGGER_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Undo activity like "like" or "dislike"
|
* @brief Undo activity like "like" or "dislike"
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* @file src/Worker/ProfileUpdate.php
|
* @file src/Worker/ProfileUpdate.php
|
||||||
* @brief Send updated profile data to Diaspora
|
* @brief Send updated profile data to Diaspora and ActivityPub
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Friendica\Worker;
|
namespace Friendica\Worker;
|
||||||
|
|
||||||
use Friendica\Protocol\Diaspora;
|
use Friendica\Protocol\Diaspora;
|
||||||
|
use Friendica\Protocol\ActivityPub;
|
||||||
|
|
||||||
class ProfileUpdate {
|
class ProfileUpdate {
|
||||||
public static function execute($uid = 0) {
|
public static function execute($uid = 0) {
|
||||||
|
@ -14,6 +15,7 @@ class ProfileUpdate {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActivityPub::transmitProfileUpdate($uid);
|
||||||
Diaspora::sendProfile($uid);
|
Diaspora::sendProfile($uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue