PluginProbe
ActivityPub / 9.1.0
ActivityPub v9.1.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / cli / class-self-destruct-command.php

class-self-destruct-command.php in ActivityPub 9.1.0, at includes/cli/class-self-destruct-command.php

304 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Self-Destruct CLI Command.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Cli;
9
10 use Activitypub\Activity\Activity;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Collection\Outbox;
13 use Activitypub\Collection\Remote_Posts;
14
15 use function Activitypub\add_to_outbox;
16
17 /**
18 * Remove the blog from the Fediverse.
19 *
20 * @package Activitypub
21 */
22 class Self_Destruct_Command extends \WP_CLI_Command {
23
24 /**
25 * Remove the entire blog from the Fediverse.
26 *
27 * This command permanently removes your blog from ActivityPub networks by sending
28 * Delete activities to all followers. This action is IRREVERSIBLE.
29 *
30 * ## OPTIONS
31 *
32 * [--status]
33 * : Check the status of the self-destruct process instead of running it.
34 * Use this to monitor progress after initiating the deletion process.
35 *
36 * [--yes]
37 * : Skip the confirmation prompt and proceed with deletion immediately.
38 * Use with extreme caution as this bypasses all safety checks.
39 *
40 * ## EXAMPLES
41 *
42 * # Start the self-destruct process (with confirmation prompt)
43 * $ wp activitypub self-destruct
44 *
45 * # Check the status of an ongoing self-destruct process
46 * $ wp activitypub self-destruct --status
47 *
48 * # Force deletion without confirmation (dangerous!)
49 * $ wp activitypub self-destruct --yes
50 *
51 * ## WHAT THIS DOES
52 *
53 * - Finds all users with ActivityPub capabilities
54 * - Creates Delete activities for each user
55 * - Sends these activities to all followers
56 * - Removes your blog from ActivityPub discovery
57 * - Sets a flag to track completion status
58 *
59 * ## IMPORTANT NOTES
60 *
61 * - This action cannot be undone
62 * - Keep the ActivityPub plugin active during the process
63 * - The process may take several minutes to complete
64 * - You will be notified when the process finishes
65 *
66 * @param array $args The positional arguments (unused).
67 * @param array $assoc_args The associative arguments (--status, --yes).
68 */
69 public function __invoke( $args, $assoc_args = array() ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
70 // Check if --status flag is provided.
71 if ( isset( $assoc_args['status'] ) ) {
72 $this->show_self_destruct_status();
73 return;
74 }
75
76 // Check if self-destruct has already been run.
77 if ( \get_option( 'activitypub_self_destruct' ) ) {
78 \WP_CLI::error( 'Self-destruct has already been initiated. The process may still be running or has completed.' . PHP_EOL . \WP_CLI::colorize( 'To check the status, run: %Bwp activitypub self-destruct --status%n' ) );
79 return;
80 }
81
82 $this->execute_self_destruct( $assoc_args );
83 }
84
85 /**
86 * Execute the self-destruct process.
87 *
88 * This method handles the actual deletion process:
89 * 1. Displays warning and confirmation prompt
90 * 2. Retrieves all ActivityPub-capable users
91 * 3. Creates and schedules Delete activities for each user
92 * 4. Sets the self-destruct flag for status tracking
93 * 5. Provides progress feedback and completion instructions
94 *
95 * @param array $assoc_args The associative arguments from WP-CLI.
96 */
97 private function execute_self_destruct( $assoc_args ) {
98 $this->display_self_destruct_warning();
99 \WP_CLI::confirm( 'Are you absolutely sure you want to continue?', $assoc_args );
100
101 $user_ids = $this->get_activitypub_users();
102 if ( empty( $user_ids ) ) {
103 \WP_CLI::warning( 'No ActivityPub users found. Nothing to delete.' );
104 return;
105 }
106
107 $processed = $this->process_user_deletions( $user_ids );
108
109 // Delete all remote posts.
110 $deleted_posts = Remote_Posts::delete_all();
111 if ( $deleted_posts > 0 ) {
112 \WP_CLI::line( \WP_CLI::colorize( "%G✓%n Deleted {$deleted_posts} remote post(s)." ) );
113 }
114
115 $this->display_completion_message( $processed );
116 }
117
118 /**
119 * Display the self-destruct warning message.
120 */
121 private function display_self_destruct_warning() {
122 \WP_CLI::line( \WP_CLI::colorize( '%R⚠️ DESTRUCTIVE OPERATION ⚠️%n' ) );
123 \WP_CLI::line( '' );
124
125 $question = 'You are about to delete your blog from the Fediverse. This action is IRREVERSIBLE and will:';
126 \WP_CLI::line( \WP_CLI::colorize( "%y{$question}%n" ) );
127 \WP_CLI::line( \WP_CLI::colorize( '%y• Send Delete activities to all followers%n' ) );
128 \WP_CLI::line( \WP_CLI::colorize( '%y• Remove your blog from ActivityPub networks%n' ) );
129 \WP_CLI::line( \WP_CLI::colorize( '%y• Delete all cached remote posts%n' ) );
130 \WP_CLI::line( '' );
131 }
132
133 /**
134 * Get all users with ActivityPub capabilities.
135 *
136 * @return array Array of user IDs with ActivityPub capabilities.
137 */
138 private function get_activitypub_users() {
139 return \get_users(
140 array(
141 'fields' => 'ID',
142 'capability__in' => array( 'activitypub' ),
143 )
144 );
145 }
146
147 /**
148 * Process user deletions and create Delete activities.
149 *
150 * @param array $user_ids Array of user IDs to process.
151 *
152 * @return int Number of users successfully processed.
153 */
154 private function process_user_deletions( $user_ids ) {
155 $user_count = \count( $user_ids );
156 \WP_CLI::line( \WP_CLI::colorize( '%GStarting Fediverse deletion process...%n' ) );
157 \WP_CLI::line( \WP_CLI::colorize( "%BFound {$user_count} ActivityPub user(s) to process:%n" ) );
158 \WP_CLI::line( '' );
159
160 // Set the self-destruct flag.
161 \update_option( 'activitypub_self_destruct', true );
162
163 $processed = 0;
164 foreach ( $user_ids as $user_id ) {
165 if ( $this->create_delete_activity_for_user( $user_id, $processed, $user_count ) ) {
166 ++$processed;
167 }
168 }
169
170 \WP_CLI::line( '' );
171
172 if ( 0 === $processed ) {
173 \WP_CLI::error( 'Failed to schedule any deletions. Please check your configuration.' );
174 }
175
176 return $processed;
177 }
178
179 /**
180 * Create a Delete activity for a specific user.
181 *
182 * @param int $user_id The user ID to process.
183 * @param int $processed Number of users already processed.
184 * @param int $user_count Total number of users to process.
185 *
186 * @return bool True if the activity was created successfully, false otherwise.
187 */
188 private function create_delete_activity_for_user( $user_id, $processed, $user_count ) {
189 $actor = Actors::get_by_id( $user_id );
190
191 if ( ! $actor ) {
192 \WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to load user ID: {$user_id}%n" ) );
193 return false;
194 }
195
196 $activity = new Activity();
197 $activity->set_actor( $actor->get_id() );
198 $activity->set_object( $actor->get_id() );
199 $activity->set_type( 'Delete' );
200
201 $result = add_to_outbox( $activity, null, $user_id );
202 if ( \is_wp_error( $result ) ) {
203 \WP_CLI::line( \WP_CLI::colorize( "%R✗ Failed to schedule deletion for: %B{$actor->get_name()}%n - {$result->get_error_message()}" ) );
204 return false;
205 }
206
207 $current = $processed + 1;
208 \WP_CLI::line( \WP_CLI::colorize( "%G✓%n [{$current}/{$user_count}] Scheduled deletion for: %B{$actor->get_name()}%n" ) );
209 return true;
210 }
211
212 /**
213 * Display the completion message after processing.
214 *
215 * @param int $processed Number of users successfully processed.
216 */
217 private function display_completion_message( $processed ) {
218 if ( 0 === $processed ) {
219 return; // Error already displayed in process_user_deletions.
220 }
221
222 \WP_CLI::success( "Successfully scheduled {$processed} user(s) for Fediverse deletion." );
223 \WP_CLI::line( '' );
224 \WP_CLI::line( \WP_CLI::colorize( '%Y📋 Next Steps:%n' ) );
225 \WP_CLI::line( \WP_CLI::colorize( '%Y• Keep the ActivityPub plugin active%n' ) );
226 \WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities will be sent automatically%n' ) );
227 \WP_CLI::line( \WP_CLI::colorize( '%Y• Process may take several minutes to complete%n' ) );
228 \WP_CLI::line( \WP_CLI::colorize( '%Y• The plugin will notify you when the process is done.%n' ) );
229 \WP_CLI::line( '' );
230 }
231
232 /**
233 * Show the status of the self-destruct process.
234 *
235 * Checks the current state of the self-destruct process by:
236 * - Verifying if the process has been initiated
237 * - Counting remaining pending Delete activities
238 * - Displaying appropriate status messages and progress
239 * - Providing guidance on next steps
240 *
241 * Status can be:
242 * - NOT STARTED: Process hasn't been initiated
243 * - IN PROGRESS: Delete activities are still being processed
244 * - COMPLETED: All Delete activities have been sent
245 */
246 private function show_self_destruct_status() {
247 // Only proceed if self-destruct is active.
248 if ( ! \get_option( 'activitypub_self_destruct', false ) ) {
249 \WP_CLI::line( \WP_CLI::colorize( '%C❌ Status: NOT STARTED%n' ) );
250 \WP_CLI::line( \WP_CLI::colorize( '%CThe self-destruct process has not been initiated.%n' ) );
251 \WP_CLI::line( '' );
252 \WP_CLI::line( \WP_CLI::colorize( '%CTo start the process, run:%n %Bwp activitypub self-destruct%n' ) );
253 \WP_CLI::line( '' );
254 return;
255 }
256
257 \WP_CLI::line( \WP_CLI::colorize( '%B🔍 Self-Destruct Status Check%n' ) );
258 \WP_CLI::line( '' );
259
260 // Check if there are any more pending Delete activities for self-destruct.
261 $pending_deletes = \get_posts(
262 array(
263 'post_type' => Outbox::POST_TYPE,
264 'post_status' => 'pending',
265 'posts_per_page' => -1,
266 'fields' => 'ids',
267 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
268 'meta_query' => array(
269 array(
270 'key' => '_activitypub_activity_type',
271 'value' => 'Delete',
272 ),
273 ),
274 )
275 );
276
277 // Get count of pending Delete activities.
278 $pending_count = \count( $pending_deletes );
279
280 // If no more pending Delete activities, self-destruct is complete.
281 if ( 0 === $pending_count ) {
282 \WP_CLI::line( \WP_CLI::colorize( '%G�
283 Status: COMPLETED%n' ) );
284 \WP_CLI::line( \WP_CLI::colorize( '%GYour blog has been successfully removed from the Fediverse.%n' ) );
285 \WP_CLI::line( '' );
286 \WP_CLI::line( \WP_CLI::colorize( '%Y📋 What happened:%n' ) );
287 \WP_CLI::line( \WP_CLI::colorize( '%Y• Delete activities were sent to all followers%n' ) );
288 \WP_CLI::line( \WP_CLI::colorize( '%Y• Your blog is no longer discoverable on ActivityPub networks%n' ) );
289 \WP_CLI::line( \WP_CLI::colorize( '%Y• The self-destruct process has finished%n' ) );
290 } else {
291 \WP_CLI::line( \WP_CLI::colorize( '%Y⏳ Status: IN PROGRESS%n' ) );
292 \WP_CLI::line( \WP_CLI::colorize( '%YThe self-destruct process is currently running.%n' ) );
293 \WP_CLI::line( '' );
294
295 \WP_CLI::line( \WP_CLI::colorize( "%YProgress: {$pending_count} Delete Activities still pending%n" ) );
296
297 \WP_CLI::line( '' );
298 \WP_CLI::line( \WP_CLI::colorize( '%YNote: The process may take several minutes to complete.%n' ) );
299 }
300
301 \WP_CLI::line( '' );
302 }
303 }
304