Skip to content

Commit

Permalink
Prevent draft posts from being federated when deleted (#1041)
Browse files Browse the repository at this point in the history
* Prevent draft posts from being federated when deleted

Fixes #1030.

* Fix end-of-file line missing

* Remove unneeded annotations

* Make sure post was federated before sending Delete

Props @pfefferle
  • Loading branch information
obenland authored Dec 5, 2024
1 parent 87d6f15 commit 5e793dd
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Prevent hex color codes in HTML attributes from being added as post tags
* Fixed a typo in the custom post content settings
* Prevent draft posts from being federated when bulk deleted

## [4.3.0] - 2024-12-02

Expand Down
30 changes: 15 additions & 15 deletions includes/class-scheduler.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,24 @@ public static function schedule_post_activity( $new_status, $old_status, $post )
return;
}

$type = false;
switch ( $new_status ) {
case 'publish':
$type = ( 'publish' === $old_status ) ? 'Update' : 'Create';
break;

if (
'publish' === $new_status &&
'publish' !== $old_status
) {
$type = 'Create';
} elseif (
'publish' === $new_status ||
// We want to send updates for posts that are published and then moved to draft.
( 'draft' === $new_status &&
'publish' === $old_status )
) {
$type = 'Update';
} elseif ( 'trash' === $new_status ) {
$type = 'Delete';
case 'draft':
$type = ( 'publish' === $old_status ) ? 'Update' : false;
break;

case 'trash':
$type = 'federated' === get_wp_object_state( $post ) ? 'Delete' : false;
break;

default:
$type = false;
}

// No activity to schedule.
if ( empty( $type ) ) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ For reasons of data protection, it is not possible to see the followers of other
* Improved: Clarified settings page text around which users get Activitypub profiles
* Fixed: Prevent hex color codes in HTML attributes from being added as post tags
* Fixed: A typo in the custom post content settings
* Fixed: Prevent draft posts from being federated when bulk deleted

= 4.3.0 =

Expand Down
219 changes: 219 additions & 0 deletions tests/class-test-scheduler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<?php
/**
* Test Scheduler class.
*
* @package ActivityPub
*/

namespace Activitypub;

/**
* Test cases for the Scheduler class.
*
* @coversDefaultClass \Activitypub\Scheduler
*/
class Test_Scheduler extends \WP_UnitTestCase {
/**
* Test post.
*
* @var \WP_Post
*/
protected $post;

/**
* Set up test resources before each test.
*
* Creates a test post in draft status.
*/
public function set_up() {
parent::set_up();

$this->post = self::factory()->post->create_and_get(
array(
'post_title' => 'Test Post',
'post_content' => 'Test Content',
'post_status' => 'draft',
'post_author' => 1,
)
);
}

/**
* Clean up test resources after each test.
*
* Deletes the test post.
*/
public function tear_down() {
wp_delete_post( $this->post->ID, true );
parent::tear_down();
}

/**
* Test that moving a draft post to trash does not schedule federation.
*
* @covers ::schedule_post_activity
*/
public function test_draft_to_trash_should_not_schedule_federation() {
Scheduler::schedule_post_activity( 'trash', 'draft', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Delete' ) ),
'Draft to trash transition should not schedule federation'
);
}

/**
* Test that moving a published post to trash schedules a delete activity only if federated.
*
* @covers ::schedule_post_activity
*/
public function test_publish_to_trash_should_schedule_delete_only_if_federated() {
wp_publish_post( $this->post->ID );
$this->post = get_post( $this->post->ID );

// Test without federation state.
Scheduler::schedule_post_activity( 'trash', 'publish', $this->post );
$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Delete' ) ),
'Published to trash transition should not schedule delete activity when not federated'
);

// Test with federation state.
set_wp_object_state( $this->post, 'federated' );
Scheduler::schedule_post_activity( 'trash', 'publish', $this->post );

$this->assertNotFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Delete' ) ),
'Published to trash transition should schedule delete activity when federated'
);
}

/**
* Test that updating a draft post does not schedule federation.
*
* @covers ::schedule_post_activity
*/
public function test_draft_to_draft_should_not_schedule_federation() {
Scheduler::schedule_post_activity( 'draft', 'draft', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Draft to draft transition should not schedule federation'
);
}

/**
* Test that moving a published post to draft schedules an update activity.
*
* @covers ::schedule_post_activity
*/
public function test_publish_to_draft_should_schedule_update() {
wp_publish_post( $this->post->ID );
$this->post = get_post( $this->post->ID );
Scheduler::schedule_post_activity( 'draft', 'publish', $this->post );

$this->assertNotFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Published to draft transition should schedule update activity'
);
}

/**
* Test that publishing a draft post schedules a create activity.
*
* @covers ::schedule_post_activity
*/
public function test_draft_to_publish_should_schedule_create() {
Scheduler::schedule_post_activity( 'publish', 'draft', $this->post );

$this->assertNotFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Create' ) ),
'Draft to publish transition should schedule create activity'
);
}

/**
* Test that updating a published post schedules an update activity.
*
* @covers ::schedule_post_activity
*/
public function test_publish_to_publish_should_schedule_update() {
wp_publish_post( $this->post->ID );
$this->post = get_post( $this->post->ID );
Scheduler::schedule_post_activity( 'publish', 'publish', $this->post );

$this->assertNotFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Published to published transition should schedule update activity'
);
}

/**
* Test that various non-standard status transitions do not schedule federation.
*
* Tests transitions from pending, private, and future statuses.
*
* @covers ::schedule_post_activity
*/
public function test_other_status_transitions_should_not_schedule_federation() {
// Test pending to draft.
Scheduler::schedule_post_activity( 'draft', 'pending', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Pending to draft transition should not schedule federation'
);

// Test private to draft.
Scheduler::schedule_post_activity( 'draft', 'private', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Private to draft transition should not schedule federation'
);

// Test future to draft.
Scheduler::schedule_post_activity( 'draft', 'future', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Update' ) ),
'Future to draft transition should not schedule federation'
);
}

/**
* Test that disabled posts do not schedule federation activities.
*
* @covers ::schedule_post_activity
*/
public function test_disabled_post_should_not_schedule_federation() {
update_post_meta( $this->post->ID, 'activitypub_content_visibility', ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL );
Scheduler::schedule_post_activity( 'publish', 'draft', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Create' ) ),
'Disabled posts should not schedule federation activities'
);
}

/**
* Test that password protected posts do not schedule federation activities.
*
* @covers ::schedule_post_activity
*/
public function test_password_protected_post_should_not_schedule_federation() {
wp_update_post(
array(
'ID' => $this->post->ID,
'post_password' => 'test-password',
)
);
$this->post = get_post( $this->post->ID );
Scheduler::schedule_post_activity( 'publish', 'draft', $this->post );

$this->assertFalse(
wp_next_scheduled( 'activitypub_send_post', array( $this->post->ID, 'Create' ) ),
'Password protected posts should not schedule federation activities'
);
}
}

0 comments on commit 5e793dd

Please sign in to comment.