Skip to:
Content

BuddyPress.org


Ignore:
Timestamp:
12/11/2021 02:13:14 PM (3 years ago)
Author:
imath
Message:

Add Ajax handlers for the recycle and delete previous avatar actions

These handlers will be used by the avatar UI:

  • to reset a previously uploaded user avatar as the current user avatar (bp_avatar_ajax_recycle_previous_avatar()),
  • to permanently remove a previously uploaded user avatar (bp_avatar_ajax_delete_previous_avatar()).

Props vapvarun, oztaser

See #8581

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-core/bp-core-avatars.php

    r13177 r13178  
    22412241    return wp_filter_object_list( $avatars, array( 'type' => $type ) );
    22422242}
     2243
     2244/**
     2245 * Recycle a previously uploaded avatar as the current avatar.
     2246 *
     2247 * @since 10.0.0
     2248 */
     2249function bp_avatar_ajax_recycle_previous_avatar() {
     2250    if ( ! bp_is_post_request() ) {
     2251        wp_send_json_error();
     2252    }
     2253
     2254    $avatar_data = bp_parse_args(
     2255        $_POST,
     2256        array(
     2257            'object'    => '',
     2258            'item_id'   => 0,
     2259            'avatar_id' => '',
     2260        )
     2261    );
     2262
     2263    if ( ! $avatar_data['object'] || ! $avatar_data['item_id'] || ! $avatar_data['avatar_id'] ) {
     2264        wp_send_json_error();
     2265    }
     2266
     2267    // Check the nonce.
     2268    check_admin_referer( 'bp_avatar_recycle_previous', 'nonce' );
     2269
     2270    // Capability check.
     2271    if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) {
     2272        wp_send_json_error();
     2273    }
     2274
     2275    // Set the Avatar Attachment Instance.
     2276    $avatar_attachment = new BP_Attachment_Avatar();
     2277    $object            = sanitize_key( $avatar_data['object'] );
     2278
     2279    if ( 'user' === $object ) {
     2280        $avatar_dir = 'avatars';
     2281    } else {
     2282        $avatar_dir = $object . '-avatars';
     2283    }
     2284
     2285    $item_id         = (int) $avatar_data['item_id'];
     2286    $avatar_dir_path = $avatar_attachment->upload_path . '/' . $avatar_dir . '/' . $item_id;
     2287    $current_avatars = bp_attachments_list_directory_files( $avatar_dir_path );
     2288    $revision_errors = array();
     2289
     2290    // This path will be needed to get the avatar revision object.
     2291    $avatar_full_revision_path = '';
     2292
     2293    // Add a revision of the current avatar if it's not a mystery man!
     2294    if ( $current_avatars ) {
     2295        foreach( $current_avatars as $current_avatar ) {
     2296            if ( ! isset( $current_avatar->name, $current_avatar->id, $current_avatar->path ) ) {
     2297                continue;
     2298            }
     2299
     2300            $is_full  = preg_match( "/-bpfull/", $current_avatar->name );
     2301            $is_thumb = preg_match( "/-bpthumb/", $current_avatar->name );
     2302
     2303            if ( $is_full || $is_thumb ) {
     2304                // Add a revision of the current avatar.
     2305                $revision = $avatar_attachment->add_revision(
     2306                    'avatar',
     2307                    array(
     2308                        'file_abspath' => $current_avatar->path,
     2309                        'file_id'      => $current_avatar->id,
     2310                    )
     2311                );
     2312
     2313                if ( is_wp_error( $revision ) ) {
     2314                    $revision_errors[] = $revision->get_error_message();
     2315                } elseif ( $is_full ) {
     2316                    $avatar_full_revision_path = $revision->path;
     2317                }
     2318            }
     2319        }
     2320    }
     2321
     2322    // No errors, let's recycle the previous avatar.
     2323    if ( ! $revision_errors ) {
     2324        $avatar_id   = sanitize_file_name( $avatar_data['avatar_id'] );
     2325        $suffix      = '-bpfull';
     2326        $history_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id . '/history';
     2327        $avatars     = bp_attachments_list_directory_files( $history_dir );
     2328
     2329        if ( ! isset( $avatars[ $avatar_id ] ) ) {
     2330            wp_send_json_error(
     2331                array(
     2332                    'message' => __( 'The profile photo you want to recycle cannot be found.', 'buddypress' ),
     2333                )
     2334            );
     2335        }
     2336
     2337        // Init recycle vars.
     2338        $recycle_timestamp = bp_core_current_time( true, 'timestamp' );
     2339        $recycle_errors    = array();
     2340        $avatar_types      = array(
     2341            'full'  => '',
     2342            'thumb' => '',
     2343        );
     2344
     2345        // Use the found previous avatar.
     2346        $avatar                = $avatars[ $avatar_id ];
     2347        $avatar_types['full']  = $avatar->path;
     2348        $avatar_types['thumb'] = str_replace( $suffix, '-bpthumb', $avatar->path );
     2349        $historical_types      = $avatar_types;
     2350
     2351        // It's a legacy avatar, we need to crop it again and remove the thumb file that is not using a timestamp in its name.
     2352        if ( ! file_exists( $avatar_types['thumb'] ) ) {
     2353            $full_avatar_path = $avatar_dir_path . '/' . str_replace( 'bpfull', 'original-file', wp_basename( $avatar->path ) );
     2354
     2355            // Move the full version back to avatar dir.
     2356            rename( $avatar->path, $full_avatar_path );
     2357
     2358            $avatar_types = $avatar_attachment->crop(
     2359                array(
     2360                    'original_file' => $full_avatar_path,
     2361                    'avatar_dir'    => $avatar_dir,
     2362                    'object'        => $object,
     2363                    'item_id'       => $item_id,
     2364                )
     2365            );
     2366
     2367            // loop into the history directory to delete the legacy thumb version file.
     2368            foreach ( $avatars as $avatar_object ) {
     2369                $timestamp = str_replace( array( '-bpthumb', '-bpfull' ), '', $avatar_object->id );
     2370
     2371                if ( ! is_numeric( $timestamp ) && false !== strpos( $avatar_object->id, '-bpthumb' ) ) {
     2372                    @unlink( $avatar_object->path );
     2373                }
     2374            }
     2375        } else {
     2376            foreach( $avatar_types as $type_key => $avatar_path ) {
     2377                $filename  = wp_basename( $avatar_path );
     2378                $avatar_id = pathinfo( $filename, PATHINFO_FILENAME );
     2379                $recycle_path = $avatar_dir_path . '/' . str_replace( $avatar_id, $recycle_timestamp . '-bp' . $type_key, $filename );
     2380
     2381                if ( ! rename( $avatar_path, $recycle_path ) ) {
     2382                    $recycle_errors[] = __( 'An unexpected error occured while recycling the previous profile photo.', 'buddypress' );
     2383                } else {
     2384                    $avatar_types[ $type_key ] = $recycle_path;
     2385                }
     2386            }
     2387
     2388            $avatar_types = array_merge(
     2389                $avatar_types,
     2390                array(
     2391                    'timestamp' => $recycle_timestamp,
     2392                )
     2393            );
     2394        }
     2395
     2396        // No errors, fire the hook used when an avatar is set.
     2397        if ( ! $recycle_errors && $historical_types['full'] !== $avatar_types['full'] ) {
     2398            $r = array(
     2399                'item_id'    => $item_id,
     2400                'object'     => $object,
     2401                'avatar_dir' => $avatar_dir,
     2402            );
     2403
     2404            $action_hook = 'bp_members_avatar_uploaded';
     2405            if ( 'group' === $object ) {
     2406                $action_hook = 'groups_avatar_uploaded';
     2407            }
     2408
     2409            /** This action is documented in bp-core/bp-core-avatars.php */
     2410            do_action( $action_hook, $item_id, 'recycle', $r, $avatar_types );
     2411        } else {
     2412            $recycle_error = reset( $recycle_errors );
     2413
     2414            wp_send_json_error(
     2415                array(
     2416                    'message' => join( "\n", $recycle_error ),
     2417                )
     2418            );
     2419        }
     2420    } else {
     2421        wp_send_json_error(
     2422            array(
     2423                'message' => join( "\n", $revision_errors ),
     2424            )
     2425        );
     2426    }
     2427
     2428    $return = array(
     2429        'avatar'        => esc_url(
     2430            bp_core_fetch_avatar(
     2431                array(
     2432                    'object'  => $object,
     2433                    'item_id' => $item_id,
     2434                    'html'    => false,
     2435                    'type'    => 'full',
     2436                )
     2437            )
     2438        ),
     2439        'feedback_code' => 5,
     2440        'item_id'       => $item_id,
     2441    );
     2442
     2443    // Get the created revision object if it exists.
     2444    if ( $avatar_full_revision_path ) {
     2445        $history_dir     = dirname( $avatar_full_revision_path );
     2446        $avatars_history = bp_attachments_list_directory_files( $history_dir );
     2447        $latest_id       = pathinfo( wp_basename( $avatar_full_revision_path ), PATHINFO_FILENAME );
     2448
     2449        if ( isset( $avatars_history[ $latest_id ] ) ) {
     2450            $gmdate      = gmdate( 'Y-m-d H:i:s', $avatars_history[ $latest_id ]->last_modified );
     2451            $date        = strtotime( get_date_from_gmt( $gmdate ) );
     2452            $history_url = trailingslashit( bp_core_avatar_url() ) .  $avatar_dir . '/' . $item_id . '/history';
     2453
     2454            // Prepare the avatar object for JavaScript.
     2455            $avatars_history[ $latest_id ]->date = sprintf(
     2456                '%1$s (%2$s)',
     2457                date_i18n( get_option( 'date_format' ), $date ),
     2458                date_i18n( get_option( 'time_format' ), $date )
     2459            );
     2460            $avatars_history[ $latest_id ]->type = 'full';
     2461            $avatars_history[ $latest_id ]->url  = $history_url . '/' . $avatars_history[ $latest_id ]->name;
     2462
     2463            // Remove the path.
     2464            unset( $avatars_history[ $latest_id ]->path );
     2465
     2466            // Set the new object to add to the revision list.
     2467            $return['historicalAvatar'] = $avatars_history[ $latest_id ];
     2468        }
     2469    }
     2470
     2471    wp_send_json_success( $return );
     2472}
     2473add_action( 'wp_ajax_bp_avatar_recycle_previous', 'bp_avatar_ajax_recycle_previous_avatar' );
     2474
     2475/**
     2476 * Delete a previously uploaded avatar from avatars history.
     2477 *
     2478 * @since 10.0.0
     2479 */
     2480function bp_avatar_ajax_delete_previous_avatar() {
     2481    if ( ! bp_is_post_request() ) {
     2482        wp_send_json_error();
     2483    }
     2484
     2485    $avatar_data = bp_parse_args(
     2486        $_POST,
     2487        array(
     2488            'object'    => '',
     2489            'item_id'   => 0,
     2490            'avatar_id' => '',
     2491        )
     2492    );
     2493
     2494    if ( ! $avatar_data['object'] || ! $avatar_data['item_id'] || ! $avatar_data['avatar_id'] ) {
     2495        wp_send_json_error();
     2496    }
     2497
     2498    // Check the nonce.
     2499    check_admin_referer( 'bp_avatar_delete_previous', 'nonce' );
     2500
     2501    // Capability check.
     2502    if ( ! bp_attachments_current_user_can( 'edit_avatar', $avatar_data ) ) {
     2503        wp_send_json_error();
     2504    }
     2505
     2506    $object = sanitize_key( $avatar_data['object'] );
     2507    if ( 'user' === $object ) {
     2508        $avatar_dir = 'avatars';
     2509    } else {
     2510        $avatar_dir = $object . '-avatars';
     2511    }
     2512
     2513    $item_id     = (int) $avatar_data['item_id'];
     2514    $avatar_id   = sanitize_file_name( $avatar_data['avatar_id'] );
     2515    $suffix      = '-bpfull';
     2516    $history_dir = trailingslashit( bp_core_avatar_upload_path() ) . $avatar_dir . '/' . $item_id . '/history';
     2517    $avatars     = bp_attachments_list_directory_files( $history_dir );
     2518
     2519    if ( ! isset( $avatars[ $avatar_id ] ) ) {
     2520        wp_send_json_error(
     2521            array(
     2522                'message' => __( 'The profile photo you want to delete cannot be found.', 'buddypress' ),
     2523            )
     2524        );
     2525    }
     2526
     2527    $avatar_types = array(
     2528        'full'  => '',
     2529        'thumb' => '',
     2530    );
     2531
     2532    // Use the found previous avatar.
     2533    $avatar                = $avatars[ $avatar_id ];
     2534    $avatar_types['full']  = $avatar->path;
     2535    $avatar_types['thumb'] = str_replace( $suffix, '-bpthumb', $avatar->path );
     2536
     2537    // It's a legacy avatar, we need to find the thumb version using file last modified date.
     2538    if ( ! file_exists( $avatar_types['thumb'] ) ) {
     2539        $avatar_types['thumb']  = '';
     2540        $possible_thumb_avatars = wp_list_pluck( $avatars, 'last_modified', 'id' );
     2541
     2542        foreach ( $possible_thumb_avatars as $type_id => $modified_date ) {
     2543            $timediff = $avatar->last_modified - $modified_date;
     2544            if ( 1000 >= absint( $timediff ) && $avatar_id !== $type_id ) {
     2545                $avatar_types['thumb'] = $avatars[ $type_id ]->path;
     2546                break;
     2547            }
     2548        }
     2549    }
     2550
     2551    // Remove the files.
     2552    foreach ( $avatar_types as $avatar_path ) {
     2553        if ( ! $avatar_path ) {
     2554            continue;
     2555        }
     2556
     2557        @unlink( $avatar_path );
     2558    }
     2559
     2560    $timestamp = str_replace( '-bpfull', '', $avatar_id );
     2561    if ( ! is_numeric( $timestamp ) ) {
     2562        $timestamp = $avatar->last_modified;
     2563    }
     2564
     2565    /**
     2566     * Hook here to run custom code once the previous avatar has been deleted.
     2567     *
     2568     * @since 10.0.0
     2569     *
     2570     * @param int $item_id   The object ID.
     2571     * @param int $timestamp The avatar timestamp.
     2572     */
     2573    do_action( "bp_previous_{$object}_avatar_deleted", $item_id, $timestamp );
     2574
     2575    // Finally inform about the deletion success.
     2576    wp_send_json_success(
     2577        array(
     2578            'feedback_code' => 6,
     2579        )
     2580    );
     2581}
     2582add_action( 'wp_ajax_bp_avatar_delete_previous', 'bp_avatar_ajax_delete_previous_avatar' );
Note: See TracChangeset for help on using the changeset viewer.