WordPress.org

Make WordPress Core


Ignore:
Timestamp:
05/02/2018 01:00:46 AM (22 months ago)
Author:
SergeyBiryukov
Message:

Privacy: update the method to confirm user requests by email. Use a single CPT to store the requests and to allow logging/audit trail.

Props mikejolley.
Merges [43008] to the 4.9 branch.
See #43443.

Location:
branches/4.9
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/4.9

  • branches/4.9/src/wp-admin/includes/user.php

    r43075 r43083  
    541541
    542542/**
    543  * Get action description from the name.
     543 * Resend an existing request and return the result.
    544544 *
    545545 * @since 4.9.6
    546546 * @access private
    547547 *
    548  * @return string
    549  */
    550 function _wp_privacy_action_description( $request_type ) {
    551     switch ( $request_type ) {
    552         case 'user_export_request':
    553             return __( 'Export Personal Data' );
    554         case 'user_remove_request':
    555             return __( 'Remove Personal Data' );
    556     }
    557 }
    558 
    559 /**
    560  * Log a request and send to the user.
    561  *
    562  * @since 4.9.6
    563  * @access private
    564  *
    565  * @param string $email_address Email address sending the request to.
    566  * @param string $action Action being requested.
    567  * @param string $description Description of request.
    568  * @return bool|WP_Error depending on success.
    569  */
    570 function _wp_privacy_create_request( $email_address, $action, $description ) {
    571     $user_id = 0;
    572     $user    = get_user_by( 'email', $email_address );
    573 
    574     if ( $user ) {
    575         $user_id = $user->ID;
    576     }
    577 
    578     $privacy_request_id = wp_insert_post( array(
    579         'post_author'   => $user_id,
    580         'post_status'   => 'request-pending',
    581         'post_type'     => $action,
    582         'post_date'     => current_time( 'mysql', false ),
    583         'post_date_gmt' => current_time( 'mysql', true ),
    584     ), true );
    585 
    586     if ( is_wp_error( $privacy_request_id ) ) {
    587         return $privacy_request_id;
    588     }
    589 
    590     update_post_meta( $privacy_request_id, '_user_email', $email_address );
    591     update_post_meta( $privacy_request_id, '_action_name', $action );
    592     update_post_meta( $privacy_request_id, '_confirmed_timestamp', false );
    593 
    594     return wp_send_account_verification_key( $email_address, $action, $description, array(
    595         'privacy_request_id' => $privacy_request_id,
    596     ) );
    597 }
    598 
    599 /**
    600  * Resend an existing request and return the result.
    601  *
    602  * @since 4.9.6
    603  * @access private
    604  *
    605  * @param int $privacy_request_id Request ID.
     548 * @param int $request_id Request ID.
    606549 * @return bool|WP_Error
    607550 */
    608 function _wp_privacy_resend_request( $privacy_request_id ) {
    609     $privacy_request_id = absint( $privacy_request_id );
    610     $privacy_request    = get_post( $privacy_request_id );
    611 
    612     if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     551function _wp_privacy_resend_request( $request_id ) {
     552    $request_id = absint( $request_id );
     553    $request    = get_post( $request_id );
     554
     555    if ( ! $request || 'user_request' !== $request->post_type ) {
    613556        return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    614557    }
    615558
    616     $email_address = get_post_meta( $privacy_request_id, '_user_email', true );
    617     $action        = get_post_meta( $privacy_request_id, '_action_name', true );
    618     $description   = _wp_privacy_action_description( $action );
    619     $result        = wp_send_account_verification_key( $email_address, $action, $description, array(
    620         'privacy_request_id' => $privacy_request_id,
    621     ) );
     559    $result = wp_send_user_request( $request_id );
    622560
    623561    if ( is_wp_error( $result ) ) {
     
    627565    }
    628566
    629     wp_update_post( array(
    630         'ID'            => $privacy_request_id,
    631         'post_status'   => 'request-pending',
    632         'post_date'     => current_time( 'mysql', false ),
    633         'post_date_gmt' => current_time( 'mysql', true ),
    634     ) );
    635 
    636567    return true;
    637568}
     
    643574 * @access private
    644575 *
    645  * @param int $privacy_request_id Request ID.
    646  * @return bool|WP_Error
    647  */
    648 function _wp_privacy_completed_request( $privacy_request_id ) {
    649     $privacy_request_id = absint( $privacy_request_id );
    650     $privacy_request    = get_post( $privacy_request_id );
    651 
    652     if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     576 * @param int $request_id Request ID.
     577 * @return int|WP_Error Request ID on succes or WP_Error.
     578 */
     579function _wp_privacy_completed_request( $request_id ) {
     580    $request_id   = absint( $request_id );
     581    $request_data = wp_get_user_request_data( $request_id );
     582
     583    if ( ! $request_data ) {
    653584        return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    654585    }
    655586
    656     wp_update_post( array(
    657         'ID'          => $privacy_request_id,
    658         'post_status' => 'request-completed',
     587    update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() );
     588    $request = wp_update_post( array(
     589        'ID'          => $request_data['request_id'],
     590        'post_status' => 'request-confirmed',
    659591    ) );
    660 
    661     update_post_meta( $privacy_request_id, '_completed_timestamp', time() );
     592    return $request;
    662593}
    663594
     
    763694                }
    764695
    765                 if ( ! empty( $email_address ) ) {
    766                     $result = _wp_privacy_create_request( $email_address, $action_type, _wp_privacy_action_description( $action_type ) );
    767 
    768                     if ( is_wp_error( $result ) ) {
    769                         add_settings_error(
    770                             'username_or_email_to_export',
    771                             'username_or_email_to_export',
    772                             $result->get_error_message(),
    773                             'error'
    774                         );
    775                     } elseif ( ! $result ) {
    776                         add_settings_error(
    777                             'username_or_email_to_export',
    778                             'username_or_email_to_export',
    779                             __( 'Unable to initiate confirmation request.' ),
    780                             'error'
    781                         );
    782                     } else {
    783                         add_settings_error(
    784                             'username_or_email_to_export',
    785                             'username_or_email_to_export',
    786                             __( 'Confirmation request initiated successfully.' ),
    787                             'updated'
    788                         );
    789                     }
     696                if ( empty( $email_address ) ) {
     697                    break;
    790698                }
     699
     700                $request_id = wp_create_user_request( $email_address, $action_type );
     701
     702                if ( is_wp_error( $request_id ) ) {
     703                    add_settings_error(
     704                        'username_or_email_to_export',
     705                        'username_or_email_to_export',
     706                        $request_id->get_error_message(),
     707                        'error'
     708                    );
     709                    break;
     710                } elseif ( ! $request_id ) {
     711                    add_settings_error(
     712                        'username_or_email_to_export',
     713                        'username_or_email_to_export',
     714                        __( 'Unable to initiate confirmation request.' ),
     715                        'error'
     716                    );
     717                    break;
     718                }
     719
     720                wp_send_user_request( $request_id );
     721
     722                add_settings_error(
     723                    'username_or_email_to_export',
     724                    'username_or_email_to_export',
     725                    __( 'Confirmation request initiated successfully.' ),
     726                    'updated'
     727                );
    791728                break;
    792729        }
     
    831768            <?php wp_nonce_field( 'personal-data-request' ); ?>
    832769            <input type="hidden" name="action" value="add_export_personal_data_request" />
    833             <input type="hidden" name="type_of_action" value="user_export_request" />
     770            <input type="hidden" name="type_of_action" value="export_personal_data" />
    834771        </form>
    835772        <hr />
     
    897834            <?php wp_nonce_field( 'personal-data-request' ); ?>
    898835            <input type="hidden" name="action" value="add_remove_personal_data_request" />
    899             <input type="hidden" name="type_of_action" value="user_remove_request" />
     836            <input type="hidden" name="type_of_action" value="remove_personal_data" />
    900837        </form>
    901838        <hr />
     
    971908    public function get_columns() {
    972909        $columns = array(
    973             'cb'         => '<input type="checkbox" />',
    974             'email'      => __( 'Requester' ),
    975             'status'     => __( 'Status' ),
    976             'requested' => __( 'Requested' ),
    977             'next_steps' => __( 'Next Steps' ),
     910            'cb'                  => '<input type="checkbox" />',
     911            'email'               => __( 'Requester' ),
     912            'status'              => __( 'Status' ),
     913            'requested_timestamp' => __( 'Requested' ),
     914            'next_steps'          => __( 'Next Steps' ),
    978915        );
    979916        return $columns;
     
    1000937    protected function get_default_primary_column_name() {
    1001938        return 'email';
     939    }
     940
     941    /**
     942     * Count number of requests for each status.
     943     *
     944     * @since 4.9.6
     945     *
     946     * @return object Number of posts for each status.
     947     */
     948    protected function get_request_counts() {
     949        global $wpdb;
     950
     951        $cache_key = $this->post_type . '-' . $this->request_type;
     952        $counts    = wp_cache_get( $cache_key, 'counts' );
     953
     954        if ( false !== $counts ) {
     955            return $counts;
     956        }
     957
     958        $query = "
     959            SELECT post_status, COUNT( * ) AS num_posts
     960            FROM {$wpdb->posts}
     961            WHERE post_type = %s
     962            AND post_title = %s
     963            GROUP BY post_status";
     964
     965        $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A );
     966        $counts  = array_fill_keys( get_post_stati(), 0 );
     967
     968        foreach ( $results as $row ) {
     969            $counts[ $row['post_status'] ] = $row['num_posts'];
     970        }
     971
     972        $counts = (object) $counts;
     973        wp_cache_set( $cache_key, $counts, 'counts' );
     974
     975        return $counts;
    1002976    }
    1003977
     
    1015989        $views          = array();
    1016990        $admin_url      = admin_url( 'tools.php?page=' . $this->request_type );
    1017         $counts         = wp_count_posts( $this->post_type );
     991        $counts         = $this->get_request_counts();
    1018992
    1019993        $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';
     
    10501024        $action      = $this->current_action();
    10511025        $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); // WPCS: input var ok, CSRF ok.
     1026        $count = 0;
    10521027
    10531028        if ( $request_ids ) {
     
    10571032        switch ( $action ) {
    10581033            case 'delete':
    1059                 $count = 0;
    1060 
    10611034                foreach ( $request_ids as $request_id ) {
    10621035                    if ( wp_delete_post( $request_id, true ) ) {
     
    10731046                break;
    10741047            case 'resend':
    1075                 $count = 0;
    1076 
    10771048                foreach ( $request_ids as $request_id ) {
    1078                     if ( _wp_privacy_resend_request( $request_id ) ) {
    1079                         $count ++;
     1049                    $resend = _wp_privacy_resend_request( $request_id );
     1050                   
     1051                    if ( $resend && ! is_wp_error( $resend ) ) {
     1052                        $count++;
    10801053                    }
    10811054                }
     
    11111084        $args           = array(
    11121085            'post_type'      => $this->post_type,
     1086            'title'          => $this->request_type,
    11131087            'posts_per_page' => $posts_per_page,
    11141088            'offset'         => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page: 0,
     
    11261100                'relation'  => 'AND',
    11271101                array(
    1128                     'key'     => '_user_email',
     1102                    'key'     => '_wp_user_request_user_email',
    11291103                    'value'   => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ): '',
    1130                     'compare' => 'LIKE'
     1104                    'compare' => 'LIKE',
    11311105                ),
    11321106            );
    11331107        }
    11341108
    1135         $privacy_requests_query = new WP_Query( $args );
    1136         $privacy_requests       = $privacy_requests_query->posts;
    1137 
    1138         foreach ( $privacy_requests as $privacy_request ) {
    1139             $this->items[] = array(
    1140                 'request_id' => $privacy_request->ID,
    1141                 'user_id'    => $privacy_request->post_author,
    1142                 'email'      => get_post_meta( $privacy_request->ID, '_user_email', true ),
    1143                 'action'     => get_post_meta( $privacy_request->ID, '_action_name', true ),
    1144                 'requested'  => strtotime( $privacy_request->post_date_gmt ),
    1145                 'confirmed'  => get_post_meta( $privacy_request->ID, '_confirmed_timestamp', true ),
    1146                 'completed'  => get_post_meta( $privacy_request->ID, '_completed_timestamp', true ),
    1147             );
     1109        $requests_query = new WP_Query( $args );
     1110        $requests       = $requests_query->posts;
     1111
     1112        foreach ( $requests as $request ) {
     1113            $this->items[] = wp_get_user_request_data( $request->ID );
    11481114        }
    11491115
    11501116        $this->set_pagination_args(
    11511117            array(
    1152                 'total_items' => $privacy_requests_query->found_posts,
     1118                'total_items' => $requests_query->found_posts,
    11531119                'per_page'    => $posts_per_page,
    11541120            )
     
    11881154        switch ( $status ) {
    11891155            case 'request-confirmed':
    1190                 $timestamp = $item['confirmed'];
     1156                $timestamp = $item['confirmed_timestamp'];
    11911157                break;
    11921158            case 'request-completed':
    1193                 $timestamp = $item['completed'];
     1159                $timestamp = $item['completed_timestamp'];
    11941160                break;
    11951161        }
     
    12391205        $cell_value = $item[ $column_name ];
    12401206
    1241         if ( in_array( $column_name, array( 'requested' ), true ) ) {
     1207        if ( in_array( $column_name, array( 'requested_timestamp' ), true ) ) {
    12421208            return $this->get_timestamp_as_date( $cell_value );
    12431209        }
     
    13121278     * @var string $post_type The post type.
    13131279     */
    1314     protected $post_type = 'user_export_request';
     1280    protected $post_type = 'user_request';
    13151281
    13161282    /**
     
    13971363     * @var string $post_type The post type.
    13981364     */
    1399     protected $post_type = 'user_remove_request';
     1365    protected $post_type = 'user_request';
    14001366
    14011367    /**
Note: See TracChangeset for help on using the changeset viewer.