-
Notifications
You must be signed in to change notification settings - Fork 82
Improved recipient handling for clarity and added better inbox support #2210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from 16 commits
523defe
51fe673
3b79444
d25fd5f
70ce80f
79429da
858672f
35dbe06
615bd19
93cf677
5e823d1
17fb6f9
2e62107
be0b67f
4d6bb2f
17ca93c
23b92ea
4ed4a4a
8a731d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: minor | ||
Type: changed | ||
|
||
Improved recipient handling for clarity and added better inbox support. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -525,40 +525,32 @@ function extract_recipients_from_activity( $data ) { | |
$recipient_items = array(); | ||
|
||
foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) { | ||
if ( array_key_exists( $i, $data ) ) { | ||
if ( is_array( $data[ $i ] ) ) { | ||
$recipient = $data[ $i ]; | ||
} else { | ||
$recipient = array( $data[ $i ] ); | ||
} | ||
$recipient_items = array_merge( $recipient_items, $recipient ); | ||
} | ||
|
||
if ( is_array( $data['object'] ) && array_key_exists( $i, $data['object'] ) ) { | ||
if ( is_array( $data['object'][ $i ] ) ) { | ||
$recipient = $data['object'][ $i ]; | ||
} else { | ||
$recipient = array( $data['object'][ $i ] ); | ||
} | ||
$recipient_items = array_merge( $recipient_items, $recipient ); | ||
} | ||
$recipient_items = array_merge( $recipient_items, extract_recipients_from_activity_property( $i, $data ) ); | ||
} | ||
|
||
return array_unique( $recipient_items ); | ||
} | ||
|
||
/** | ||
* Extract recipient URLs from a specific property of an Activity object. | ||
* | ||
* @param string $property The property to extract recipients from (e.g., 'to', 'cc'). | ||
* @param array $data The Activity object as array. | ||
* | ||
* @return array The list of user URLs. | ||
*/ | ||
function extract_recipients_from_activity_property( $property, $data ) { | ||
$recipients = array(); | ||
|
||
// Flatten array. | ||
foreach ( $recipient_items as $recipient ) { | ||
if ( is_array( $recipient ) ) { | ||
// Check if recipient is an object. | ||
if ( array_key_exists( 'id', $recipient ) ) { | ||
$recipients[] = $recipient['id']; | ||
} | ||
} else { | ||
$recipients[] = $recipient; | ||
} | ||
if ( ! empty( $data[ $property ] ) ) { | ||
$recipients = $data[ $property ]; | ||
} elseif ( ! empty( $data['object'][ $property ] ) ) { | ||
$recipients = $data['object'][ $property ]; | ||
} | ||
|
||
return array_unique( $recipients ); | ||
$recipients = \array_map( '\Activitypub\object_to_uri', (array) $recipients ); | ||
|
||
return \array_unique( \array_filter( $recipients ) ); | ||
} | ||
|
||
/** | ||
|
@@ -696,7 +688,7 @@ function url_to_commentid( $url ) { | |
* | ||
* @param array|string $data The ActivityPub object. | ||
* | ||
* @return string The URI of the ActivityPub object | ||
* @return string|false The URI of the ActivityPub object or false if not found. | ||
|
||
*/ | ||
function object_to_uri( $data ) { | ||
// Check whether it is already simple. | ||
|
@@ -733,10 +725,10 @@ function object_to_uri( $data ) { | |
$data = object_to_uri( $data['url'] ); | ||
break; | ||
case 'Link': | ||
$data = $data['href']; | ||
$data = $data['href'] ?? false; | ||
pfefferle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
break; | ||
default: | ||
$data = $data['id']; | ||
$data = $data['id'] ?? $data['url'] ?? false; | ||
break; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ | |
*/ | ||
class Actors_Inbox_Controller extends Actors_Controller { | ||
use Collection; | ||
use Audience; | ||
|
||
/** | ||
* Register routes. | ||
|
@@ -177,24 +178,28 @@ public function create_item( $request ) { | |
*/ | ||
do_action( 'activitypub_rest_inbox_disallowed', $data, $user_id, $type, $activity ); | ||
} else { | ||
$visibility = $this->determine_visibility( $data ); | ||
|
||
/** | ||
* ActivityPub inbox action. | ||
* | ||
* @param array $data The data array. | ||
* @param int|null $user_id The user ID. | ||
* @param string $type The type of the activity. | ||
* @param Activity|\WP_Error $activity The Activity object. | ||
* @param array $data The data array. | ||
* @param int|null $user_id The user ID. | ||
* @param string $type The type of the activity. | ||
* @param Activity|\WP_Error $activity The Activity object. | ||
* @param string $visibility The visibility of the activity. | ||
*/ | ||
\do_action( 'activitypub_inbox', $data, $user_id, $type, $activity ); | ||
\do_action( 'activitypub_inbox', $data, $user_id, $type, $activity, $visibility ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not quite clear to me why the visibility stuff needs to be moved up a level, when (so far) it's only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, we are currently only use it for Aside from that, we are about to implement the reader, so we might want to have a more detailed visibility handling and not only a "Public or not". |
||
|
||
/** | ||
* ActivityPub inbox action for specific activity types. | ||
* | ||
* @param array $data The data array. | ||
* @param int|null $user_id The user ID. | ||
* @param Activity|\WP_Error $activity The Activity object. | ||
* @param array $data The data array. | ||
* @param int|null $user_id The user ID. | ||
* @param Activity|\WP_Error $activity The Activity object. | ||
* @param string $visibility The visibility of the activity. | ||
*/ | ||
\do_action( 'activitypub_inbox_' . $type, $data, $user_id, $activity ); | ||
\do_action( 'activitypub_inbox_' . $type, $data, $user_id, $activity, $visibility ); | ||
} | ||
|
||
$response = \rest_ensure_response( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
/** | ||
* Audience Trait file. | ||
* | ||
* @package Activitypub | ||
*/ | ||
|
||
namespace Activitypub\Rest; | ||
|
||
use Activitypub\Collection\Actors; | ||
|
||
use function Activitypub\extract_recipients_from_activity; | ||
use function Activitypub\extract_recipients_from_activity_property; | ||
use function Activitypub\is_same_domain; | ||
use function Activitypub\user_can_activitypub; | ||
|
||
/** | ||
* Audience Trait. | ||
* | ||
* Provides methods for handling ActivityPub audience and recipient extraction. | ||
*/ | ||
trait Audience { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could these be methods in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if we check the Audience, this is not a function I see in the Actors Collection! I will see if I can move it to the Activity. |
||
/** | ||
* Extract recipients from the given Activity. | ||
* | ||
* @param array $activity The activity data. | ||
* | ||
* @return array An array of user IDs who are the recipients of the activity. | ||
*/ | ||
public function determine_local_recipients( $activity ) { | ||
pfefferle marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
$recipients = extract_recipients_from_activity( $activity ); | ||
$user_ids = array(); | ||
|
||
foreach ( $recipients as $recipient ) { | ||
|
||
if ( ! is_same_domain( $recipient ) ) { | ||
continue; | ||
} | ||
|
||
$user_id = Actors::get_id_by_resource( $recipient ); | ||
|
||
if ( \is_wp_error( $user_id ) ) { | ||
continue; | ||
} | ||
|
||
if ( ! user_can_activitypub( $user_id ) ) { | ||
continue; | ||
} | ||
|
||
$user_ids[] = $user_id; | ||
} | ||
|
||
return $user_ids; | ||
} | ||
|
||
/** | ||
* Determine the visibility of the activity based on its recipients. | ||
* | ||
* @param array $activity The activity data. | ||
* | ||
* @return string The visibility level: 'public', 'private', or 'direct'. | ||
*/ | ||
public function determine_visibility( $activity ) { | ||
pfefferle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Set default visibility for specific activity types. | ||
if ( in_array( $activity['type'], array( 'Accept', 'Delete', 'Follow', 'Reject', 'Undo' ), true ) ) { | ||
return ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE; | ||
} | ||
|
||
// Check 'to' field for public visibility. | ||
$to = extract_recipients_from_activity_property( 'to', $activity ); | ||
if ( ! empty( array_intersect( $to, ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS ) ) ) { | ||
return ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC; | ||
} | ||
|
||
// Check 'cc' field for quiet public visibility. | ||
$cc = extract_recipients_from_activity_property( 'cc', $activity ); | ||
if ( ! empty( array_intersect( $cc, ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS ) ) ) { | ||
return ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC; | ||
} | ||
|
||
return ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.