Skip to content

Commit 51ce666

Browse files
obenlandpfefferle
andauthored
Following: Undo the correct Follow activity (#1905)
Co-authored-by: Matthias Pfefferle <[email protected]>
1 parent 06d9341 commit 51ce666

File tree

4 files changed

+147
-3
lines changed

4 files changed

+147
-3
lines changed

includes/collection/class-following.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static function reject( $post, $user_id ) {
107107
* @param \WP_Post|int $post The ID of the remote Actor.
108108
* @param int $user_id The ID of the WordPress User.
109109
*
110-
* @return \WP_Post|\WP_Error The ID of the Actor or a WP_Error.
110+
* @return \WP_Post|\WP_Error The Actor post or a WP_Error.
111111
*/
112112
public static function unfollow( $post, $user_id ) {
113113
$post = \get_post( $post );
@@ -116,6 +116,8 @@ public static function unfollow( $post, $user_id ) {
116116
return new \WP_Error( 'activitypub_remote_actor_not_found', __( 'Remote actor not found', 'activitypub' ) );
117117
}
118118

119+
$actor_type = Actors::get_type_by_id( $user_id );
120+
119121
\delete_post_meta( $post->ID, self::FOLLOWING_META_KEY, $user_id );
120122
\delete_post_meta( $post->ID, self::PENDING_META_KEY, $user_id );
121123

@@ -125,6 +127,7 @@ public static function unfollow( $post, $user_id ) {
125127
'post_type' => Outbox::POST_TYPE,
126128
'nopaging' => true,
127129
'posts_per_page' => 1,
130+
'author' => \max( $user_id, 0 ),
128131
'fields' => 'ids',
129132
'number' => 1,
130133
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
@@ -133,6 +136,14 @@ public static function unfollow( $post, $user_id ) {
133136
'key' => '_activitypub_object_id',
134137
'value' => $post->guid,
135138
),
139+
array(
140+
'key' => '_activitypub_activity_type',
141+
'value' => 'Follow',
142+
),
143+
array(
144+
'key' => '_activitypub_activity_actor',
145+
'value' => $actor_type,
146+
),
136147
),
137148
)
138149
);

includes/functions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ function add_to_outbox( $data, $activity_type = null, $user_id = 0, $content_vis
15321532
* @param string $remote_actor The Actor URL.
15331533
* @param int $user_id The ID of the WordPress User.
15341534
*
1535-
* @return int|\WP_Error The ID of the Actor or a WP_Error.
1535+
* @return int|\WP_Error The ID of the Outbox item or a WP_Error.
15361536
*/
15371537
function follow( $remote_actor, $user_id ) {
15381538
$remote_actor_post = Actors::fetch_remote_by_uri( $remote_actor );

templates/user-following-list.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
<form method="post">
1919
<input type="hidden" name="page" value="activitypub-following-list" />
20-
<?php wp_nonce_field( 'bulk-' . $table->_args['plural'] ); ?>
2120
<?php
21+
wp_nonce_field( 'bulk-' . $table->_args['plural'] );
2222
$table->prepare_items();
2323
$table->search_box( 'Search', 'search' );
2424
$table->display();

tests/includes/collection/class-test-following.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
use Activitypub\Collection\Actors;
1111
use Activitypub\Collection\Following;
12+
use Activitypub\Handler\Accept;
13+
14+
use function Activitypub\follow;
1215

1316
/**
1417
* Class Test_Following
@@ -329,4 +332,134 @@ public function test_unfollow_removes_user() {
329332

330333
\wp_delete_post( $post_id );
331334
}
335+
336+
/**
337+
* Tests unfollow method.
338+
*
339+
* @covers ::unfollow
340+
*/
341+
public function test_unfollow() {
342+
\add_filter( 'activitypub_pre_http_get_remote_object', array( $this, 'mock_remote_actor' ), 10, 2 );
343+
344+
$user_ids = self::factory()->user->create_many( 3 );
345+
foreach ( $user_ids as $user_id ) {
346+
\get_user_by( 'id', $user_id )->add_cap( 'activitypub' );
347+
}
348+
349+
$outbox_item_1 = \get_post( follow( 'https://example.com/actor/1', $user_ids[0] ) );
350+
$outbox_item_2 = \get_post( follow( 'https://example.com/actor/1', $user_ids[1] ) );
351+
$outbox_item_3 = \get_post( follow( 'https://example.com/actor/1', $user_ids[2] ) );
352+
$outbox_item_4 = \get_post( follow( 'https://example.com/actor/1', 0 ) );
353+
$outbox_item_5 = \get_post( follow( 'https://example.com/actor/1', -1 ) );
354+
355+
\wp_publish_post( $outbox_item_1 );
356+
\wp_publish_post( $outbox_item_2 );
357+
\wp_publish_post( $outbox_item_3 );
358+
\wp_publish_post( $outbox_item_4 );
359+
\wp_publish_post( $outbox_item_5 );
360+
361+
$accept_1 = array(
362+
'object' => array(
363+
'id' => $outbox_item_1->guid,
364+
'actor' => 'https://example.com/actor/1',
365+
),
366+
);
367+
$accept_2 = array(
368+
'object' => array(
369+
'id' => $outbox_item_2->guid,
370+
'actor' => 'https://example.com/actor/1',
371+
),
372+
);
373+
$accept_3 = array(
374+
'object' => array(
375+
'id' => $outbox_item_3->guid,
376+
'actor' => 'https://example.com/actor/1',
377+
),
378+
);
379+
$accept_4 = array(
380+
'object' => array(
381+
'id' => $outbox_item_4->guid,
382+
'actor' => 'https://example.com/actor/1',
383+
),
384+
);
385+
$accept_5 = array(
386+
'object' => array(
387+
'id' => $outbox_item_5->guid,
388+
'actor' => 'https://example.com/actor/1',
389+
),
390+
);
391+
392+
Accept::handle_accept( $accept_1, $user_ids[0] );
393+
Accept::handle_accept( $accept_2, $user_ids[1] );
394+
Accept::handle_accept( $accept_3, $user_ids[2] );
395+
Accept::handle_accept( $accept_4, 0 );
396+
Accept::handle_accept( $accept_5, -1 );
397+
398+
// User 1 follows https://example.com/actor/1.
399+
$following = Following::get_following_with_count( $user_ids[0] );
400+
$this->assertCount( 1, $following['following'] );
401+
$this->assertSame( 1, $following['total'] );
402+
403+
$following = Following::get_following_with_count( -1 );
404+
$this->assertCount( 1, $following['following'] );
405+
$this->assertSame( 1, $following['total'] );
406+
407+
// User 3 unfollows https://example.com/actor/1.
408+
Following::unfollow( Actors::get_remote_by_uri( 'https://example.com/actor/1' ), $user_ids[2] );
409+
410+
// User 3 unfollows https://example.com/actor/1.
411+
Following::unfollow( Actors::get_remote_by_uri( 'https://example.com/actor/1' ), 0 );
412+
413+
$following = Following::get_following_with_count( 0 );
414+
$this->assertCount( 0, $following['following'] );
415+
$this->assertSame( 0, $following['total'] );
416+
417+
$following = Following::get_following_with_count( -1 );
418+
$this->assertCount( 1, $following['following'] );
419+
$this->assertSame( 1, $following['total'] );
420+
421+
// User 1 still follows https://example.com/actor/1.
422+
$posts = get_posts(
423+
array(
424+
'post_type' => 'ap_outbox',
425+
'post_status' => 'any',
426+
'author' => $user_ids[2],
427+
'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
428+
array(
429+
'key' => '_activitypub_object_id',
430+
'value' => 'https://example.com/actor/1',
431+
),
432+
array(
433+
'key' => '_activitypub_activity_type',
434+
'value' => 'Undo',
435+
),
436+
),
437+
)
438+
);
439+
440+
// There should be an Undo post for user 3.
441+
$this->assertCount( 1, $posts );
442+
}
443+
444+
/**
445+
* Mock remote actor.
446+
*
447+
* @param array $response The response.
448+
* @param string $url The URL.
449+
*
450+
* @return array
451+
*/
452+
public function mock_remote_actor( $response, $url ) {
453+
if ( 'https://example.com/actor/1' === $url ) {
454+
$response = array(
455+
'id' => $url,
456+
'type' => 'Person',
457+
'url' => $url,
458+
'name' => 'John Doe',
459+
'inbox' => 'https://example.com/inbox',
460+
);
461+
}
462+
463+
return $response;
464+
}
332465
}

0 commit comments

Comments
 (0)