Skip to content

Commit b022733

Browse files
authored
Fix: Properly traverse the object hierarchy to get the ID (#1518)
1 parent d14cbfe commit b022733

File tree

7 files changed

+235
-103
lines changed

7 files changed

+235
-103
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: fixed
3+
4+
Support multiple layers of nested Outbox activities when searching for the Object ID.

includes/activity/class-activity.php

Lines changed: 91 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
namespace Activitypub\Activity;
1111

12-
use Activitypub\Link;
12+
use Activitypub\Activity\Extended_Object\Event;
13+
use Activitypub\Activity\Extended_Object\Place;
1314

1415
/**
1516
* \Activitypub\Activity\Activity implements the common
@@ -23,6 +24,43 @@ class Activity extends Base_Object {
2324
'https://www.w3.org/ns/activitystreams',
2425
);
2526

27+
/**
28+
* The default types for Activities.
29+
*
30+
* @see https://www.w3.org/TR/activitystreams-vocabulary/#activity-types
31+
*
32+
* @var array
33+
*/
34+
const TYPES = array(
35+
'Accept',
36+
'Add',
37+
'Announce',
38+
'Arrive',
39+
'Block',
40+
'Create',
41+
'Delete',
42+
'Dislike',
43+
'Follow',
44+
'Flag',
45+
'Ignore',
46+
'Invite',
47+
'Join',
48+
'Leave',
49+
'Like',
50+
'Listen',
51+
'Move',
52+
'Offer',
53+
'Read',
54+
'Reject',
55+
'Remove',
56+
'TentativeAccept',
57+
'TentativeReject',
58+
'Travel',
59+
'Undo',
60+
'Update',
61+
'View',
62+
);
63+
2664
/**
2765
* The type of the object.
2866
*
@@ -124,58 +162,87 @@ class Activity extends Base_Object {
124162
*
125163
* @see https://www.w3.org/TR/activitypub/#object-without-create
126164
*
127-
* @param array|string|Base_Object|Link|null $data Activity object.
165+
* @param array|string|Base_Object|Activity|Actor|null $data Activity object.
128166
*/
129167
public function set_object( $data ) {
130-
// Convert array to object.
168+
$object = $data;
169+
170+
// Convert array to appropriate object type.
131171
if ( is_array( $data ) ) {
132-
$data = Generic_Object::init_from_array( $data );
172+
$type = $data['type'] ?? null;
173+
174+
if ( in_array( $type, self::TYPES, true ) ) {
175+
$object = self::init_from_array( $data );
176+
} elseif ( in_array( $type, Actor::TYPES, true ) ) {
177+
$object = Actor::init_from_array( $data );
178+
} elseif ( in_array( $type, Base_Object::TYPES, true ) ) {
179+
switch ( $type ) {
180+
case 'Event':
181+
$object = Event::init_from_array( $data );
182+
break;
183+
case 'Place':
184+
$object = Place::init_from_array( $data );
185+
break;
186+
default:
187+
$object = Base_Object::init_from_array( $data );
188+
break;
189+
}
190+
} else {
191+
$object = Generic_Object::init_from_array( $data );
192+
}
133193
}
134194

135-
// Set object.
136-
$this->set( 'object', $data );
195+
$this->set( 'object', $object );
196+
$this->pre_fill_activity_from_object();
197+
}
198+
199+
/**
200+
* Fills the Activity with the specified activity object.
201+
*/
202+
public function pre_fill_activity_from_object() {
203+
$object = $this->get_object();
137204

138205
// Check if `$data` is a URL and use it to generate an ID then.
139-
if ( is_string( $data ) && filter_var( $data, FILTER_VALIDATE_URL ) && ! $this->get_id() ) {
140-
$this->set( 'id', $data . '#activity-' . strtolower( $this->get_type() ) . '-' . time() );
206+
if ( is_string( $object ) && filter_var( $object, FILTER_VALIDATE_URL ) && ! $this->get_id() ) {
207+
$this->set( 'id', $object . '#activity-' . strtolower( $this->get_type() ) . '-' . time() );
141208

142209
return;
143210
}
144211

145212
// Check if `$data` is an object and copy some properties otherwise do nothing.
146-
if ( ! is_object( $data ) ) {
213+
if ( ! is_object( $object ) ) {
147214
return;
148215
}
149216

150217
foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) {
151-
$value = $data->get( $i );
218+
$value = $object->get( $i );
152219
if ( $value && ! $this->get( $i ) ) {
153220
$this->set( $i, $value );
154221
}
155222
}
156223

157-
if ( $data->get_published() && ! $this->get_published() ) {
158-
$this->set( 'published', $data->get_published() );
224+
if ( $object->get_published() && ! $this->get_published() ) {
225+
$this->set( 'published', $object->get_published() );
159226
}
160227

161-
if ( $data->get_updated() && ! $this->get_updated() ) {
162-
$this->set( 'updated', $data->get_updated() );
228+
if ( $object->get_updated() && ! $this->get_updated() ) {
229+
$this->set( 'updated', $object->get_updated() );
163230
}
164231

165-
if ( $data->get_attributed_to() && ! $this->get_actor() ) {
166-
$this->set( 'actor', $data->get_attributed_to() );
232+
if ( $object->get_attributed_to() && ! $this->get_actor() ) {
233+
$this->set( 'actor', $object->get_attributed_to() );
167234
}
168235

169-
if ( $data->get_in_reply_to() && ! $this->get_in_reply_to() ) {
170-
$this->set( 'in_reply_to', $data->get_in_reply_to() );
236+
if ( $object->get_in_reply_to() && ! $this->get_in_reply_to() ) {
237+
$this->set( 'in_reply_to', $object->get_in_reply_to() );
171238
}
172239

173-
if ( $data->get_id() && ! $this->get_id() ) {
174-
$id = strtok( $data->get_id(), '#' );
175-
if ( $data->get_updated() ) {
176-
$updated = $data->get_updated();
177-
} elseif ( $data->get_published() ) {
178-
$updated = $data->get_published();
240+
if ( $object->get_id() && ! $this->get_id() ) {
241+
$id = strtok( $object->get_id(), '#' );
242+
if ( $object->get_updated() ) {
243+
$updated = $object->get_updated();
244+
} elseif ( $object->get_published() ) {
245+
$updated = $object->get_published();
179246
} else {
180247
$updated = time();
181248
}

includes/activity/class-actor.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ class Actor extends Base_Object {
6161
),
6262
);
6363

64+
/**
65+
* The default types for Actors.
66+
*
67+
* @see https://www.w3.org/TR/activitystreams-vocabulary/#actor-types
68+
*
69+
* @var array
70+
*/
71+
const TYPES = array(
72+
'Application',
73+
'Group',
74+
'Organization',
75+
'Person',
76+
'Service',
77+
);
78+
6479
/**
6580
* The type of the object.
6681
*

includes/activity/class-base-object.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,28 @@ class Base_Object extends Generic_Object {
7878
),
7979
);
8080

81+
/**
82+
* The default types for Objects.
83+
*
84+
* @see https://www.w3.org/TR/activitystreams-vocabulary/#object-types
85+
*
86+
* @var array
87+
*/
88+
const TYPES = array(
89+
'Article',
90+
'Audio',
91+
'Document',
92+
'Event',
93+
'Image',
94+
'Note',
95+
'Page',
96+
'Place',
97+
'Profile',
98+
'Relationship',
99+
'Tombstone',
100+
'Video',
101+
);
102+
81103
/**
82104
* The type of the object.
83105
*

includes/collection/class-outbox.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Activitypub\Dispatcher;
1111
use Activitypub\Scheduler;
1212
use Activitypub\Activity\Activity;
13+
use Activitypub\Activity\Base_Object;
1314

1415
use function Activitypub\add_to_outbox;
1516

@@ -296,28 +297,29 @@ public static function maybe_get_activity( $outbox_item ) {
296297
/**
297298
* Get the object ID of an activity.
298299
*
299-
* @param Activity $activity The activity object.
300+
* @param Activity|Base_Object|string $data The activity object.
301+
*
300302
* @return string The object ID.
301303
*/
302-
private static function get_object_id( $activity ) {
303-
// Most common.
304-
if ( is_object( $activity->get_object() ) ) {
305-
return $activity->get_object()->get_id();
304+
private static function get_object_id( $data ) {
305+
$object = $data->get_object();
306+
307+
if ( is_object( $object ) ) {
308+
return self::get_object_id( $object );
306309
}
307310

308-
// Rare.
309-
if ( is_string( $activity->get_object() ) ) {
310-
return $activity->get_object();
311+
if ( is_string( $object ) ) {
312+
return $object;
311313
}
312314

313-
// Exceptional.
314-
return $activity->get_actor() ?? $activity->get_id();
315+
return $data->get_id() ?? $data->get_actor();
315316
}
316317

317318
/**
318319
* Get the title of an activity recursively.
319320
*
320-
* @param \Activitypub\Activity\Base_Object $activity_object The activity object.
321+
* @param Base_Object $activity_object The activity object.
322+
*
321323
* @return string The title.
322324
*/
323325
private static function get_object_title( $activity_object ) {
@@ -333,7 +335,7 @@ private static function get_object_title( $activity_object ) {
333335

334336
$title = $activity_object->get_name() ?? $activity_object->get_content();
335337

336-
if ( ! $title && $activity_object->get_object() instanceof \Activitypub\Activity\Base_Object ) {
338+
if ( ! $title && $activity_object->get_object() instanceof Base_Object ) {
337339
$title = $activity_object->get_object()->get_name() ?? $activity_object->get_object()->get_content();
338340
}
339341

includes/functions.php

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use WP_Error;
1111
use Activitypub\Activity\Activity;
12+
use Activitypub\Activity\Actor;
1213
use Activitypub\Activity\Base_Object;
1314
use Activitypub\Collection\Actors;
1415
use Activitypub\Collection\Outbox;
@@ -1535,38 +1536,7 @@ function is_activity( $data ) {
15351536
*
15361537
* @param array $types The activity types.
15371538
*/
1538-
$types = apply_filters(
1539-
'activitypub_activity_types',
1540-
array(
1541-
'Accept',
1542-
'Add',
1543-
'Announce',
1544-
'Arrive',
1545-
'Block',
1546-
'Create',
1547-
'Delete',
1548-
'Dislike',
1549-
'Follow',
1550-
'Flag',
1551-
'Ignore',
1552-
'Invite',
1553-
'Join',
1554-
'Leave',
1555-
'Like',
1556-
'Listen',
1557-
'Move',
1558-
'Offer',
1559-
'Read',
1560-
'Reject',
1561-
'Remove',
1562-
'TentativeAccept',
1563-
'TentativeReject',
1564-
'Travel',
1565-
'Undo',
1566-
'Update',
1567-
'View',
1568-
)
1569-
);
1539+
$types = apply_filters( 'activitypub_activity_types', Activity::TYPES );
15701540

15711541
if ( is_string( $data ) ) {
15721542
return in_array( $data, $types, true );
@@ -1598,16 +1568,7 @@ function is_actor( $data ) {
15981568
*
15991569
* @param array $types The actor types.
16001570
*/
1601-
$types = apply_filters(
1602-
'activitypub_actor_types',
1603-
array(
1604-
'Application',
1605-
'Group',
1606-
'Organization',
1607-
'Person',
1608-
'Service',
1609-
)
1610-
);
1571+
$types = apply_filters( 'activitypub_actor_types', Actor::TYPES );
16111572

16121573
if ( is_string( $data ) ) {
16131574
return in_array( $data, $types, true );

0 commit comments

Comments
 (0)