Make WordPress Core


Ignore:
Timestamp:
04/27/2018 10:12:01 AM (8 years ago)
Author:
azaozz
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.
See #43443.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/user.php

    r43000 r43008  
    582582
    583583/**
    584  * Get action description from the name.
     584 * Resend an existing request and return the result.
    585585 *
    586586 * @since 4.9.6
    587587 * @access private
    588588 *
    589  * @return string
    590  */
    591 function _wp_privacy_action_description( $request_type ) {
    592         switch ( $request_type ) {
    593                 case 'user_export_request':
    594                         return __( 'Export Personal Data' );
    595                 case 'user_remove_request':
    596                         return __( 'Remove Personal Data' );
    597         }
    598 }
    599 
    600 /**
    601  * Log a request and send to the user.
    602  *
    603  * @since 4.9.6
    604  * @access private
    605  *
    606  * @param string $email_address Email address sending the request to.
    607  * @param string $action Action being requested.
    608  * @param string $description Description of request.
    609  * @return bool|WP_Error depending on success.
    610  */
    611 function _wp_privacy_create_request( $email_address, $action, $description ) {
    612         $user_id = 0;
    613         $user    = get_user_by( 'email', $email_address );
    614 
    615         if ( $user ) {
    616                 $user_id = $user->ID;
    617         }
    618 
    619         $privacy_request_id = wp_insert_post( array(
    620                 'post_author'   => $user_id,
    621                 'post_status'   => 'request-pending',
    622                 'post_type'     => $action,
    623                 'post_date'     => current_time( 'mysql', false ),
    624                 'post_date_gmt' => current_time( 'mysql', true ),
    625         ), true );
    626 
    627         if ( is_wp_error( $privacy_request_id ) ) {
    628                 return $privacy_request_id;
    629         }
    630 
    631         update_post_meta( $privacy_request_id, '_user_email', $email_address );
    632         update_post_meta( $privacy_request_id, '_action_name', $action );
    633         update_post_meta( $privacy_request_id, '_confirmed_timestamp', false );
    634 
    635         return wp_send_account_verification_key( $email_address, $action, $description, array(
    636                 'privacy_request_id' => $privacy_request_id,
    637         ) );
    638 }
    639 
    640 /**
    641  * Resend an existing request and return the result.
    642  *
    643  * @since 4.9.6
    644  * @access private
    645  *
    646  * @param int $privacy_request_id Request ID.
     589 * @param int $request_id Request ID.
    647590 * @return bool|WP_Error
    648591 */
    649 function _wp_privacy_resend_request( $privacy_request_id ) {
    650         $privacy_request_id = absint( $privacy_request_id );
    651         $privacy_request    = get_post( $privacy_request_id );
    652 
    653         if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     592function _wp_privacy_resend_request( $request_id ) {
     593        $request_id = absint( $request_id );
     594        $request    = get_post( $request_id );
     595
     596        if ( ! $request || 'user_request' !== $request->post_type ) {
    654597                return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    655598        }
    656599
    657         $email_address = get_post_meta( $privacy_request_id, '_user_email', true );
    658         $action        = get_post_meta( $privacy_request_id, '_action_name', true );
    659         $description   = _wp_privacy_action_description( $action );
    660         $result        = wp_send_account_verification_key( $email_address, $action, $description, array(
    661                 'privacy_request_id' => $privacy_request_id,
    662         ) );
     600        $result = wp_send_user_request( $request_id );
    663601
    664602        if ( is_wp_error( $result ) ) {
     
    668606        }
    669607
    670         wp_update_post( array(
    671                 'ID'            => $privacy_request_id,
    672                 'post_status'   => 'request-pending',
    673                 'post_date'     => current_time( 'mysql', false ),
    674                 'post_date_gmt' => current_time( 'mysql', true ),
    675         ) );
    676 
    677608        return true;
    678609}
     
    684615 * @access private
    685616 *
    686  * @param int $privacy_request_id Request ID.
    687  * @return bool|WP_Error
    688  */
    689 function _wp_privacy_completed_request( $privacy_request_id ) {
    690         $privacy_request_id = absint( $privacy_request_id );
    691         $privacy_request    = get_post( $privacy_request_id );
    692 
    693         if ( ! $privacy_request || ! in_array( $privacy_request->post_type, _wp_privacy_action_request_types(), true ) ) {
     617 * @param int $request_id Request ID.
     618 * @return int|WP_Error Request ID on succes or WP_Error.
     619 */
     620function _wp_privacy_completed_request( $request_id ) {
     621        $request_id   = absint( $request_id );
     622        $request_data = wp_get_user_request_data( $request_id );
     623
     624        if ( ! $request_data ) {
    694625                return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    695626        }
    696627
    697         wp_update_post( array(
    698                 'ID'          => $privacy_request_id,
    699                 'post_status' => 'request-completed',
     628        update_post_meta( $request_id, '_wp_user_request_confirmed_timestamp', time() );
     629        $request = wp_update_post( array(
     630                'ID'          => $request_data['request_id'],
     631                'post_status' => 'request-confirmed',
    700632        ) );
    701 
    702         update_post_meta( $privacy_request_id, '_completed_timestamp', time() );
     633        return $request;
    703634}
    704635
     
    804735                                }
    805736
    806                                 if ( ! empty( $email_address ) ) {
    807                                         $result = _wp_privacy_create_request( $email_address, $action_type, _wp_privacy_action_description( $action_type ) );
    808 
    809                                         if ( is_wp_error( $result ) ) {
    810                                                 add_settings_error(
    811                                                         'username_or_email_to_export',
    812                                                         'username_or_email_to_export',
    813                                                         $result->get_error_message(),
    814                                                         'error'
    815                                                 );
    816                                         } elseif ( ! $result ) {
    817                                                 add_settings_error(
    818                                                         'username_or_email_to_export',
    819                                                         'username_or_email_to_export',
    820                                                         __( 'Unable to initiate confirmation request.' ),
    821                                                         'error'
    822                                                 );
    823                                         } else {
    824                                                 add_settings_error(
    825                                                         'username_or_email_to_export',
    826                                                         'username_or_email_to_export',
    827                                                         __( 'Confirmation request initiated successfully.' ),
    828                                                         'updated'
    829                                                 );
    830                                         }
     737                                if ( empty( $email_address ) ) {
     738                                        break;
    831739                                }
     740
     741                                $request_id = wp_create_user_request( $email_address, $action_type );
     742
     743                                if ( is_wp_error( $request_id ) ) {
     744                                        add_settings_error(
     745                                                'username_or_email_to_export',
     746                                                'username_or_email_to_export',
     747                                                $request_id->get_error_message(),
     748                                                'error'
     749                                        );
     750                                        break;
     751                                } elseif ( ! $request_id ) {
     752                                        add_settings_error(
     753                                                'username_or_email_to_export',
     754                                                'username_or_email_to_export',
     755                                                __( 'Unable to initiate confirmation request.' ),
     756                                                'error'
     757                                        );
     758                                        break;
     759                                }
     760
     761                                wp_send_user_request( $request_id );
     762
     763                                add_settings_error(
     764                                        'username_or_email_to_export',
     765                                        'username_or_email_to_export',
     766                                        __( 'Confirmation request initiated successfully.' ),
     767                                        'updated'
     768                                );
    832769                                break;
    833770                }
     
    872809                        <?php wp_nonce_field( 'personal-data-request' ); ?>
    873810                        <input type="hidden" name="action" value="add_export_personal_data_request" />
    874                         <input type="hidden" name="type_of_action" value="user_export_request" />
     811                        <input type="hidden" name="type_of_action" value="export_personal_data" />
    875812                </form>
    876813                <hr />
     
    938875                        <?php wp_nonce_field( 'personal-data-request' ); ?>
    939876                        <input type="hidden" name="action" value="add_remove_personal_data_request" />
    940                         <input type="hidden" name="type_of_action" value="user_remove_request" />
     877                        <input type="hidden" name="type_of_action" value="remove_personal_data" />
    941878                </form>
    942879                <hr />
     
    1012949        public function get_columns() {
    1013950                $columns = array(
    1014                         'cb'         => '<input type="checkbox" />',
    1015                         'email'      => __( 'Requester' ),
    1016                         'status'     => __( 'Status' ),
    1017                         'requested' => __( 'Requested' ),
    1018                         'next_steps' => __( 'Next Steps' ),
     951                        'cb'                  => '<input type="checkbox" />',
     952                        'email'               => __( 'Requester' ),
     953                        'status'              => __( 'Status' ),
     954                        'requested_timestamp' => __( 'Requested' ),
     955                        'next_steps'          => __( 'Next Steps' ),
    1019956                );
    1020957                return $columns;
     
    1041978        protected function get_default_primary_column_name() {
    1042979                return 'email';
     980        }
     981
     982        /**
     983         * Count number of requests for each status.
     984         *
     985         * @since 4.9.6
     986         *
     987         * @return object Number of posts for each status.
     988         */
     989        protected function get_request_counts() {
     990                global $wpdb;
     991
     992                $cache_key = $this->post_type . '-' . $this->request_type;
     993                $counts    = wp_cache_get( $cache_key, 'counts' );
     994
     995                if ( false !== $counts ) {
     996                        return $counts;
     997                }
     998
     999                $query = "
     1000                        SELECT post_status, COUNT( * ) AS num_posts
     1001                        FROM {$wpdb->posts}
     1002                        WHERE post_type = %s
     1003                        AND post_title = %s
     1004                        GROUP BY post_status";
     1005
     1006                $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A );
     1007                $counts  = array_fill_keys( get_post_stati(), 0 );
     1008
     1009                foreach ( $results as $row ) {
     1010                        $counts[ $row['post_status'] ] = $row['num_posts'];
     1011                }
     1012
     1013                $counts = (object) $counts;
     1014                wp_cache_set( $cache_key, $counts, 'counts' );
     1015
     1016                return $counts;
    10431017        }
    10441018
     
    10561030                $views          = array();
    10571031                $admin_url      = admin_url( 'tools.php?page=' . $this->request_type );
    1058                 $counts         = wp_count_posts( $this->post_type );
     1032                $counts         = $this->get_request_counts();
    10591033
    10601034                $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';
     
    10911065                $action      = $this->current_action();
    10921066                $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); // WPCS: input var ok, CSRF ok.
     1067                $count = 0;
    10931068
    10941069                if ( $request_ids ) {
     
    10981073                switch ( $action ) {
    10991074                        case 'delete':
    1100                                 $count = 0;
    1101 
    11021075                                foreach ( $request_ids as $request_id ) {
    11031076                                        if ( wp_delete_post( $request_id, true ) ) {
     
    11141087                                break;
    11151088                        case 'resend':
    1116                                 $count = 0;
    1117 
    11181089                                foreach ( $request_ids as $request_id ) {
    1119                                         if ( _wp_privacy_resend_request( $request_id ) ) {
    1120                                                 $count ++;
     1090                                        $resend = _wp_privacy_resend_request( $request_id );
     1091                                       
     1092                                        if ( $resend && ! is_wp_error( $resend ) ) {
     1093                                                $count++;
    11211094                                        }
    11221095                                }
     
    11521125                $args           = array(
    11531126                        'post_type'      => $this->post_type,
     1127                        'title'          => $this->request_type,
    11541128                        'posts_per_page' => $posts_per_page,
    11551129                        'offset'         => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page: 0,
     
    11671141                                'relation'  => 'AND',
    11681142                                array(
    1169                                         'key'     => '_user_email',
     1143                                        'key'     => '_wp_user_request_user_email',
    11701144                                        'value'   => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ): '',
    1171                                         'compare' => 'LIKE'
     1145                                        'compare' => 'LIKE',
    11721146                                ),
    11731147                        );
    11741148                }
    11751149
    1176                 $privacy_requests_query = new WP_Query( $args );
    1177                 $privacy_requests       = $privacy_requests_query->posts;
    1178 
    1179                 foreach ( $privacy_requests as $privacy_request ) {
    1180                         $this->items[] = array(
    1181                                 'request_id' => $privacy_request->ID,
    1182                                 'user_id'    => $privacy_request->post_author,
    1183                                 'email'      => get_post_meta( $privacy_request->ID, '_user_email', true ),
    1184                                 'action'     => get_post_meta( $privacy_request->ID, '_action_name', true ),
    1185                                 'requested'  => strtotime( $privacy_request->post_date_gmt ),
    1186                                 'confirmed'  => get_post_meta( $privacy_request->ID, '_confirmed_timestamp', true ),
    1187                                 'completed'  => get_post_meta( $privacy_request->ID, '_completed_timestamp', true ),
    1188                         );
     1150                $requests_query = new WP_Query( $args );
     1151                $requests       = $requests_query->posts;
     1152
     1153                foreach ( $requests as $request ) {
     1154                        $this->items[] = wp_get_user_request_data( $request->ID );
    11891155                }
    11901156
    11911157                $this->set_pagination_args(
    11921158                        array(
    1193                                 'total_items' => $privacy_requests_query->found_posts,
     1159                                'total_items' => $requests_query->found_posts,
    11941160                                'per_page'    => $posts_per_page,
    11951161                        )
     
    12291195                switch ( $status ) {
    12301196                        case 'request-confirmed':
    1231                                 $timestamp = $item['confirmed'];
     1197                                $timestamp = $item['confirmed_timestamp'];
    12321198                                break;
    12331199                        case 'request-completed':
    1234                                 $timestamp = $item['completed'];
     1200                                $timestamp = $item['completed_timestamp'];
    12351201                                break;
    12361202                }
     
    12801246                $cell_value = $item[ $column_name ];
    12811247
    1282                 if ( in_array( $column_name, array( 'requested' ), true ) ) {
     1248                if ( in_array( $column_name, array( 'requested_timestamp' ), true ) ) {
    12831249                        return $this->get_timestamp_as_date( $cell_value );
    12841250                }
     
    13531319         * @var string $post_type The post type.
    13541320         */
    1355         protected $post_type = 'user_export_request';
     1321        protected $post_type = 'user_request';
    13561322
    13571323        /**
     
    14381404         * @var string $post_type The post type.
    14391405         */
    1440         protected $post_type = 'user_remove_request';
     1406        protected $post_type = 'user_request';
    14411407
    14421408        /**
Note: See TracChangeset for help on using the changeset viewer.