Changeset 43012
- Timestamp:
- 04/27/2018 07:53:37 PM (7 years ago)
- Location:
- trunk/src
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/includes/admin-filters.php
r43008 r43012 133 133 add_action( 'upgrader_process_complete', 'wp_update_themes', 10, 0 ); 134 134 135 // Privacy hooks 136 add_filter( 'wp_privacy_personal_data_export_page', 'wp_privacy_process_personal_data_export_page', 10, 6 ); 137 add_action( 'wp_privacy_personal_data_export_file', 'wp_privacy_generate_personal_data_export_file', 10 ); 138 135 139 // Privacy policy text changes check. 136 140 add_action( 'admin_init', array( 'WP_Privacy_Policy_Content', 'text_change_check' ), 20 ); … … 144 148 // Stop checking for text changes after the policy page is updated. 145 149 add_action( 'post_updated', array( 'WP_Privacy_Policy_Content', '_policy_page_updated' ) ); 146 -
trunk/src/wp-admin/includes/ajax-actions.php
r43011 r43012 4328 4328 } 4329 4329 4330 /** 4331 * Ajax handler for exporting a user's personal data. 4332 * 4333 * @since 4.9.6 4334 */ 4330 4335 function wp_ajax_wp_privacy_export_personal_data() { 4331 check_ajax_referer( 'wp-privacy-export-personal-data', 'security' ); 4336 $request_id = (int) $_POST['id']; 4337 4338 if ( empty( $request_id ) ) { 4339 wp_send_json_error( __( 'Error: Invalid request ID.' ) ); 4340 } 4332 4341 4333 4342 if ( ! current_user_can( 'manage_options' ) ) { … … 4335 4344 } 4336 4345 4337 $email_address = sanitize_text_field( $_POST['email'] ); 4346 check_ajax_referer( 'wp-privacy-export-personal-data-' . $request_id, 'security' ); 4347 4348 // Get the request data. 4349 $request = wp_get_user_request_data( $request_id ); 4350 4351 if ( ! $request || 'export_personal_data' !== $request->action_name ) { 4352 wp_send_json_error( __( 'Error: Invalid request type.' ) ); 4353 } 4354 4355 $email_address = $request->email; 4356 if ( ! is_email( $email_address ) ) { 4357 wp_send_json_error( __( 'Error: A valid email address must be given.' ) ); 4358 } 4359 4338 4360 $exporter_index = (int) $_POST['exporter']; 4339 4361 $page = (int) $_POST['page']; 4362 $send_as_email = isset( $_POST['sendAsEmail'] ) ? ( "true" === $_POST['sendAsEmail'] ) : false; 4340 4363 4341 4364 /** … … 4349 4372 * callback string Callable exporter that accepts an email address and 4350 4373 * a page and returns an array of name => value 4351 * pairs of personal data 4352 * exporter_friendly_name string Translated user facing friendly name for the exporter 4374 * pairs of personal data. 4375 * exporter_friendly_name string Translated user facing friendly name for the exporter. 4353 4376 * ] 4354 4377 * } … … 4376 4399 } 4377 4400 4378 // Surprisingly, email addresses can contain mutli-byte characters now4379 $email_address = trim( mb_strtolower( $email_address ) );4380 4381 if ( ! is_email( $email_address ) ) {4382 wp_send_json_error( 'A valid email address must be given.' );4383 }4384 4385 4401 $exporter = $exporters[ $index ]; 4402 4386 4403 if ( ! is_array( $exporter ) ) { 4387 4404 wp_send_json_error( "Expected an array describing the exporter at index {$exporter_index}." ); 4388 4405 } 4389 if ( ! array_key_exists( 'callback', $exporter ) ) {4390 wp_send_json_error( "Exporter array at index {$exporter_index} does not include a callback." );4391 }4392 if ( ! is_callable( $exporter['callback'] ) ) {4393 wp_send_json_error( "Exporter callback at index {$exporter_index} is not a valid callback." );4394 }4395 4406 if ( ! array_key_exists( 'exporter_friendly_name', $exporter ) ) { 4396 4407 wp_send_json_error( "Exporter array at index {$exporter_index} does not include a friendly name." ); 4408 } 4409 if ( ! array_key_exists( 'callback', $exporter ) ) { 4410 wp_send_json_error( "Exporter does not include a callback: {$exporter['exporter_friendly_name']}." ); 4411 } 4412 if ( ! is_callable( $exporter['callback'] ) ) { 4413 wp_send_json_error( "Exporter callback is not a valid callback: {$exporter['exporter_friendly_name']}." ); 4397 4414 } 4398 4415 … … 4418 4435 } 4419 4436 } else { 4420 // No exporters, so we're done 4437 // No exporters, so we're done. 4421 4438 $response = array( 4422 4439 'data' => array(), … … 4436 4453 * @param string $email_address The email address associated with this personal data. 4437 4454 * @param int $page The zero-based page for this response. 4455 * @param int $request_id The privacy request post ID associated with this request. 4456 * @param bool $send_as_email Whether the final results of the export should be emailed to the user. 4438 4457 */ 4439 $response = apply_filters( 'wp_privacy_personal_data_export_page', $response, $exporter_index, $email_address, $page ); 4458 $response = apply_filters( 'wp_privacy_personal_data_export_page', $response, $exporter_index, $email_address, $page, $request_id, $send_as_email ); 4459 4440 4460 if ( is_wp_error( $response ) ) { 4441 4461 wp_send_json_error( $response ); … … 4463 4483 check_ajax_referer( 'wp-privacy-erase-personal-data-' . $request_id, 'security' ); 4464 4484 4465 // Find the request CPT4485 // Get the request data. 4466 4486 $request = wp_get_user_request_data( $request_id ); 4467 4487 -
trunk/src/wp-admin/includes/file.php
r42983 r43012 1935 1935 <?php 1936 1936 } 1937 1938 /** 1939 * Generate a single group for the personal data export report. 1940 * 1941 * @since 4.9.6 1942 * 1943 * @param array $group_data { 1944 * The group data to render. 1945 * 1946 * @type string $group_label The user-facing heading for the group, e.g. 'Comments'. 1947 * @type array $items { 1948 * An array of group items. 1949 * 1950 * @type array $group_item_data { 1951 * An array of name-value pairs for the item. 1952 * 1953 * @type string $name The user-facing name of an item name-value pair, e.g. 'IP Address'. 1954 * @type string $value The user-facing value of an item data pair, e.g. '50.60.70.0'. 1955 * } 1956 * } 1957 * } 1958 * @return string The HTML for this group and its items. 1959 */ 1960 function wp_privacy_generate_personal_data_export_group_html( $group_data ) { 1961 $allowed_tags = array( 1962 'a' => array( 1963 'href' => array(), 1964 'target' => array() 1965 ), 1966 'br' => array() 1967 ); 1968 $allowed_protocols = array( 'http', 'https' ); 1969 $group_html = ''; 1970 1971 $group_html .= '<h2>' . esc_html( $group_data['group_label'] ) . '</h2>'; 1972 $group_html .= '<div>'; 1973 1974 foreach ( (array) $group_data['items'] as $group_item_id => $group_item_data ) { 1975 $group_html .= '<table>'; 1976 $group_html .= '<tbody>'; 1977 1978 foreach ( (array) $group_item_data as $group_item_datum ) { 1979 $group_html .= '<tr>'; 1980 $group_html .= '<th>' . esc_html( $group_item_datum['name'] ) . '</th>'; 1981 $group_html .= '<td>' . wp_kses( $group_item_datum['value'], $allowed_tags, $allowed_protocols ) . '</td>'; 1982 $group_html .= '</tr>'; 1983 } 1984 1985 $group_html .= '</tbody>'; 1986 $group_html .= '</table>'; 1987 } 1988 1989 $group_html .= '</div>'; 1990 1991 return $group_html; 1992 } 1993 1994 /** 1995 * Generate the personal data export file. 1996 * 1997 * @since 4.9.6 1998 * 1999 * @param int $request_id The export request ID. 2000 */ 2001 function wp_privacy_generate_personal_data_export_file( $request_id ) { 2002 // Maybe make this a cron job instead. 2003 wp_privacy_delete_old_export_files(); 2004 2005 if ( ! class_exists( 'ZipArchive' ) ) { 2006 wp_send_json_error( __( 'Unable to generate export file. ZipArchive not available.' ) ); 2007 } 2008 2009 // Get the request data. 2010 $request = wp_get_user_request_data( $request_id ); 2011 2012 if ( ! $request || 'export_personal_data' !== $request->action_name ) { 2013 wp_send_json_error( __( 'Invalid request ID when generating export file' ) ); 2014 } 2015 2016 $email_address = $request->email; 2017 2018 if ( ! is_email( $email_address ) ) { 2019 wp_send_json_error( __( 'Invalid email address when generating export file' ) ); 2020 } 2021 2022 // Create the exports folder if needed. 2023 $upload_dir = wp_upload_dir(); 2024 $exports_dir = trailingslashit( $upload_dir['basedir'] . '/exports' ); 2025 $exports_url = trailingslashit( $upload_dir['baseurl'] . '/exports' ); 2026 2027 $result = wp_mkdir_p( $exports_dir ); 2028 if ( is_wp_error( $result ) ) { 2029 wp_send_json_error( $result->get_error_message() ); 2030 } 2031 2032 // Protect export folder from browsing. 2033 $index_pathname = $exports_dir . 'index.html'; 2034 if ( ! file_exists( $index_pathname ) ) { 2035 $file = fopen( $index_pathname, 'w' ); 2036 if ( false === $file ) { 2037 wp_send_json_error( __( 'Unable to protect export folder from browsing' ) ); 2038 } 2039 fwrite( $file, 'Silence is golden.' ); 2040 fclose( $file ); 2041 } 2042 2043 $stripped_email = str_replace( '@', '-at-', $email_address ); 2044 $stripped_email = sanitize_title( $stripped_email ); // slugify the email address 2045 $obscura = md5( rand() ); 2046 $file_basename = 'wp-personal-data-file-' . $stripped_email . '-' . $obscura; 2047 $html_report_filename = $file_basename . '.html'; 2048 $html_report_pathname = $exports_dir . $html_report_filename; 2049 $file = fopen( $html_report_pathname, 'w' ); 2050 if ( false === $file ) { 2051 wp_send_json_error( __( 'Unable to open export file (HTML report) for writing' ) ); 2052 } 2053 2054 $title = sprintf( 2055 // translators: %s Users e-mail address. 2056 __( 'Personal Data Export for %s' ), 2057 $email_address 2058 ); 2059 2060 // Open HTML. 2061 fwrite( $file, "<!DOCTYPE html>\n" ); 2062 fwrite( $file, "<html>\n" ); 2063 2064 // Head. 2065 fwrite( $file, "<head>\n" ); 2066 fwrite( $file, "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n" ); 2067 fwrite( $file, "<style type='text/css'>" ); 2068 fwrite( $file, "body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }" ); 2069 fwrite( $file, "table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }" ); 2070 fwrite( $file, "th { padding: 5px; text-align: left; width: 20%; }" ); 2071 fwrite( $file, "td { padding: 5px; }" ); 2072 fwrite( $file, "tr:nth-child(odd) { background-color: #fafafa; }" ); 2073 fwrite( $file, "</style>" ); 2074 fwrite( $file, "<title>" ); 2075 fwrite( $file, esc_html( $title ) ); 2076 fwrite( $file, "</title>" ); 2077 fwrite( $file, "</head>\n" ); 2078 2079 // Body. 2080 fwrite( $file, "<body>\n" ); 2081 2082 // Heading. 2083 fwrite( $file, "<h1>" . esc_html__( 'Personal Data Export' ) . "</h1>" ); 2084 2085 // And now, all the Groups. 2086 $groups = get_post_meta( $request_id, '_export_data_grouped', true ); 2087 2088 // First, build an "About" group on the fly for this report. 2089 $about_group = array( 2090 'group_label' => __( 'About' ), 2091 'items' => array( 2092 'about-1' => array( 2093 array( 2094 'name' => __( 'Report generated for' ), 2095 'value' => $email_address, 2096 ), 2097 array( 2098 'name' => __( 'For site' ), 2099 'value' => get_bloginfo( 'name' ), 2100 ), 2101 array( 2102 'name' => __( 'At URL' ), 2103 'value' => get_bloginfo( 'url' ), 2104 ), 2105 array( 2106 'name' => __( 'On' ), 2107 'value' => current_time( 'mysql' ), 2108 ), 2109 ), 2110 ), 2111 ); 2112 2113 // Merge in the special about group. 2114 $groups = array_merge( array( 'about' => $about_group ), $groups ); 2115 2116 // Now, iterate over every group in $groups and have the formatter render it in HTML. 2117 foreach ( (array) $groups as $group_id => $group_data ) { 2118 fwrite( $file, wp_privacy_generate_personal_data_export_group_html( $group_data ) ); 2119 } 2120 2121 fwrite( $file, "</body>\n" ); 2122 2123 // Close HTML. 2124 fwrite( $file, "</html>\n" ); 2125 fclose( $file ); 2126 2127 // Now, generate the ZIP. 2128 $archive_filename = $file_basename . '.zip'; 2129 $archive_pathname = $exports_dir . $archive_filename; 2130 $archive_url = $exports_url . $archive_filename; 2131 2132 $zip = new ZipArchive; 2133 2134 if ( TRUE === $zip->open( $archive_pathname, ZipArchive::CREATE ) ) { 2135 $zip->addFile( $html_report_pathname, 'index.html' ); 2136 $zip->close(); 2137 } else { 2138 wp_send_json_error( __( 'Unable to open export file (archive) for writing' ) ); 2139 } 2140 2141 // And remove the HTML file. 2142 unlink( $html_report_pathname ); 2143 2144 // Save the export file in the request. 2145 update_post_meta( $request_id, '_export_file_url', $archive_url ); 2146 update_post_meta( $request_id, '_export_file_path', $archive_pathname ); 2147 } 2148 2149 /** 2150 * Send an email to the user with a link to the personal data export file 2151 * 2152 * @since 4.9.6 2153 * 2154 * @param int $request_id The request ID for this personal data export. 2155 * @return true|WP_Error True on success or `WP_Error` on failure. 2156 */ 2157 function wp_privacy_send_personal_data_export_email( $request_id ) { 2158 // Get the request data. 2159 $request = wp_get_user_request_data( $request_id ); 2160 2161 if ( ! $request || 'export_personal_data' !== $request->action_name ) { 2162 return new WP_Error( 'invalid', __( 'Invalid request ID when sending personal data export email.' ) ); 2163 } 2164 2165 /* translators: Do not translate LINK, EMAIL, SITENAME, SITEURL: those are placeholders. */ 2166 $email_text = __( 2167 'Howdy, 2168 2169 Your request for an export of personal data has been completed. You may 2170 download your personal data by clicking on the link below. This link is 2171 good for the next 3 days. 2172 2173 ###LINK### 2174 2175 This email has been sent to ###EMAIL###. 2176 2177 Regards, 2178 All at ###SITENAME### 2179 ###SITEURL###' 2180 ); 2181 2182 /** 2183 * Filters the text of the email sent with a personal data export file. 2184 * 2185 * The following strings have a special meaning and will get replaced dynamically: 2186 * ###LINK### URL of the personal data export file for the user. 2187 * ###EMAIL### The email we are sending to. 2188 * ###SITENAME### The name of the site. 2189 * ###SITEURL### The URL to the site. 2190 * 2191 * @since 4.9.6 2192 * 2193 * @param string $email_text Text in the email. 2194 * @param int $request_id The request ID for this personal data export. 2195 */ 2196 $content = apply_filters( 'wp_privacy_personal_data_email_content', $email_text, $request_id ); 2197 2198 $email_address = $request->email; 2199 $export_file_url = get_post_meta( $request_id, '_export_file_url', true ); 2200 $site_name = is_multisite() ? get_site_option( 'site_name' ) : get_option( 'blogname' ); 2201 $site_url = network_home_url(); 2202 2203 $content = str_replace( '###LINK###', esc_url_raw( $export_file_url ), $content ); 2204 $content = str_replace( '###EMAIL###', $email_address, $content ); 2205 $content = str_replace( '###SITENAME###', wp_specialchars_decode( $site_name, ENT_QUOTES ), $content ); 2206 $content = str_replace( '###SITEURL###', esc_url_raw( $site_url ), $content ); 2207 2208 $mail_success = wp_mail( 2209 $email_address, 2210 sprintf( 2211 __( '[%s] Personal Data Export' ), 2212 wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ) 2213 ), 2214 $content 2215 ); 2216 2217 if ( ! $mail_success ) { 2218 return new WP_Error( 'error', __( 'Unable to send personal data export email.' ) ); 2219 } 2220 2221 return true; 2222 } 2223 2224 /** 2225 * Intercept personal data exporter page ajax responses in order to assemble the personal data export file. 2226 * @see wp_privacy_personal_data_export_page 2227 * @since 4.9.6 2228 * 2229 * @param array $response The response from the personal data exporter for the given page. 2230 * @param int $exporter_index The index of the personal data exporter. Begins at 1. 2231 * @param string $email_address The email address of the user whose personal data this is. 2232 * @param int $page The page of personal data for this exporter. Begins at 1. 2233 * @param int $request_id The request ID for this personal data export. 2234 * @param bool $send_as_email Whether the final results of the export should be emailed to the user. 2235 * @return array The filtered response. 2236 */ 2237 function wp_privacy_process_personal_data_export_page( $response, $exporter_index, $email_address, $page, $request_id, $send_as_email ) { 2238 /* Do some simple checks on the shape of the response from the exporter. 2239 * If the exporter response is malformed, don't attempt to consume it - let it 2240 * pass through to generate a warning to the user by default ajax processing. 2241 */ 2242 if ( ! is_array( $response ) ) { 2243 return $response; 2244 } 2245 2246 if ( ! array_key_exists( 'done', $response ) ) { 2247 return $response; 2248 } 2249 2250 if ( ! array_key_exists( 'data', $response ) ) { 2251 return $response; 2252 } 2253 2254 if ( ! is_array( $response['data'] ) ) { 2255 return $response; 2256 } 2257 2258 // Get the request data. 2259 $request = wp_get_user_request_data( $request_id ); 2260 2261 if ( ! $request || 'export_personal_data' !== $request->action_name ) { 2262 wp_send_json_error( __( 'Invalid request ID when merging exporter data' ) ); 2263 } 2264 2265 $export_data = array(); 2266 2267 // First exporter, first page? Reset the report data accumulation array. 2268 if ( 1 === $exporter_index && 1 === $page ) { 2269 update_post_meta( $request_id, '_export_data_raw', $export_data ); 2270 } else { 2271 $export_data = get_post_meta( $request_id, '_export_data_raw', true ); 2272 } 2273 2274 // Now, merge the data from the exporter response into the data we have accumulated already. 2275 $export_data = array_merge( $export_data, $response['data'] ); 2276 update_post_meta( $request_id, '_export_data_raw', $export_data ); 2277 2278 // If we are not yet on the last page of the last exporter, return now. 2279 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); 2280 $is_last_exporter = $exporter_index === count( $exporters ); 2281 $exporter_done = $response['done']; 2282 if ( ! $is_last_exporter || ! $exporter_done ) { 2283 return $response; 2284 } 2285 2286 // Last exporter, last page - let's prepare the export file. 2287 2288 // First we need to re-organize the raw data hierarchically in groups and items. 2289 $groups = array(); 2290 foreach ( (array) $export_data as $export_datum ) { 2291 $group_id = $export_datum['group_id']; 2292 $group_label = $export_datum['group_label']; 2293 if ( ! array_key_exists( $group_id, $groups ) ) { 2294 $groups[ $group_id ] = array( 2295 'group_label' => $group_label, 2296 'items' => array(), 2297 ); 2298 } 2299 2300 $item_id = $export_datum['item_id']; 2301 if ( ! array_key_exists( $item_id, $groups[ $group_id ]['items'] ) ) { 2302 $groups[ $group_id ]['items'][ $item_id ] = array(); 2303 } 2304 2305 $old_item_data = $groups[ $group_id ]['items'][ $item_id ]; 2306 $merged_item_data = array_merge( $export_datum['data'], $old_item_data ); 2307 $groups[ $group_id ]['items'][ $item_id ] = $merged_item_data; 2308 } 2309 2310 // Then save the grouped data into the request. 2311 delete_post_meta( $request_id, '_export_data_raw' ); 2312 update_post_meta( $request_id, '_export_data_grouped', $groups ); 2313 2314 // And now, generate the export file, cleaning up any previous file 2315 $export_path = get_post_meta( $request_id, '_export_file_path', true ); 2316 if ( ! empty( $export_path ) ) { 2317 delete_post_meta( $request_id, '_export_file_path' ); 2318 @unlink( $export_path ); 2319 } 2320 delete_post_meta( $request_id, '_export_file_url' ); 2321 2322 // Generate the export file from the collected, grouped personal data. 2323 do_action( 'wp_privacy_personal_data_export_file', $request_id ); 2324 2325 // Clear the grouped data now that it is no longer needed. 2326 delete_post_meta( $request_id, '_export_data_grouped' ); 2327 2328 // If the destination is email, send it now. 2329 if ( $send_as_email ) { 2330 $mail_success = wp_privacy_send_personal_data_export_email( $request_id ); 2331 if ( is_wp_error( $mail_success ) ) { 2332 wp_send_json_error( $mail_success->get_error_message() ); 2333 } 2334 } else { 2335 // Modify the response to include the URL of the export file so the browser can fetch it. 2336 $export_file_url = get_post_meta( $request_id, '_export_file_url', true ); 2337 if ( ! empty( $export_file_url ) ) { 2338 $response['url'] = $export_file_url; 2339 } 2340 } 2341 2342 // Update the request to completed state. 2343 _wp_privacy_completed_request( $request_id ); 2344 2345 return $response; 2346 } 2347 2348 /** 2349 * Cleans up export files older than three days old. 2350 * 2351 * @since 4.9.6 2352 */ 2353 function wp_privacy_delete_old_export_files() { 2354 $upload_dir = wp_upload_dir(); 2355 $exports_dir = trailingslashit( $upload_dir['basedir'] . '/exports' ); 2356 $export_files = list_files( $exports_dir ); 2357 2358 foreach( (array) $export_files as $export_file ) { 2359 $file_age_in_seconds = time() - filemtime( $export_file ); 2360 2361 if ( 3 * DAY_IN_SECONDS < $file_age_in_seconds ) { 2362 @unlink( $export_file ); 2363 } 2364 } 2365 } -
trunk/src/wp-admin/includes/user.php
r43011 r43012 661 661 'privacy_action_email_retry', 662 662 __( 'Confirmation request re-resent successfully.' ), 663 'updated'664 );665 }666 667 } elseif ( isset( $_POST['export_personal_data_email_send'] ) ) { // WPCS: input var ok.668 check_admin_referer( 'bulk-privacy_requests' );669 670 $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['export_personal_data_email_send'] ) ) ) ); // WPCS: input var ok, sanitization ok.671 $result = false;672 673 /**674 * TODO: Email the data to the user here.675 */676 677 if ( is_wp_error( $result ) ) {678 add_settings_error(679 'export_personal_data_email_send',680 'export_personal_data_email_send',681 $result->get_error_message(),682 'error'683 );684 } else {685 _wp_privacy_completed_request( $request_id );686 add_settings_error(687 'export_personal_data_email_send',688 'export_personal_data_email_send',689 __( 'Personal data was sent to the user successfully.' ),690 663 'updated' 691 664 ); … … 820 793 _wp_personal_data_cleanup_requests(); 821 794 795 // "Borrow" xfn.js for now so we don't have to create new files. 796 wp_enqueue_script( 'xfn' ); 797 822 798 $requests_table = new WP_Privacy_Data_Export_Requests_Table( array( 823 799 'plural' => 'privacy_requests', … … 1362 1338 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); 1363 1339 1364 $download_data_markup = '<div class=" download_personal_data" ' .1340 $download_data_markup = '<div class="export_personal_data" ' . 1365 1341 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . 1366 1342 'data-request-id="' . esc_attr( $request_id ) . '" ' . … … 1368 1344 '">'; 1369 1345 1370 $download_data_markup .= '<span class="download_personal_data_idle"><a href="#" >' . __( 'Download Personal Data' ) . '</a></span>' . 1371 '<span style="display:none" class="download_personal_data_processing" >' . __( 'Downloading Data...' ) . '</span>' . 1372 '<span style="display:none" class="download_personal_data_failed">' . __( 'Download Failed!' ) . ' <a href="#" >' . __( 'Retry' ) . '</a></span>'; 1346 $download_data_markup .= '<span class="export_personal_data_idle"><a href="#" >' . __( 'Download Personal Data' ) . '</a></span>' . 1347 '<span style="display:none" class="export_personal_data_processing" >' . __( 'Downloading Data...' ) . '</span>' . 1348 '<span style="display:none" class="export_personal_data_success"><a href="#" >' . __( 'Download Personal Data Again' ) . '</a></span>' . 1349 '<span style="display:none" class="export_personal_data_failed">' . __( 'Download Failed!' ) . ' <a href="#" >' . __( 'Retry' ) . '</a></span>'; 1350 1351 $download_data_markup .= '</div>'; 1373 1352 1374 1353 $row_actions = array( … … 1394 1373 break; 1395 1374 case 'request-confirmed': 1396 // TODO Complete in follow on patch. 1375 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); 1376 $exporters_count = count( $exporters ); 1377 $request_id = $item->ID; 1378 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); 1379 1380 echo '<div class="export_personal_data" ' . 1381 'data-send-as-email="1" ' . 1382 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' . 1383 'data-request-id="' . esc_attr( $request_id ) . '" ' . 1384 'data-nonce="' . esc_attr( $nonce ) . 1385 '">'; 1386 1387 ?> 1388 <span class="export_personal_data_idle"><a class="button" href="#" ><?php _e( 'Email Data' ); ?></a></span> 1389 <span style="display:none" class="export_personal_data_processing button updating-message" ><?php _e( 'Sending Email...' ); ?></span> 1390 <span style="display:none" class="export_personal_data_success success-message" ><?php _e( 'Email Sent!' ); ?></span> 1391 <span style="display:none" class="export_personal_data_failed"><?php _e( 'Email Failed!' ); ?> <a class="button" href="#" ><?php _e( 'Retry' ); ?></a></span> 1392 <?php 1393 1394 echo '</div>'; 1397 1395 break; 1398 1396 case 'request-failed': … … 1462 1460 '<span style="display:none" class="remove_personal_data_failed">' . __( 'Force Remove Failed!' ) . ' <a href="#" >' . __( 'Retry' ) . '</a></span>'; 1463 1461 1462 $remove_data_markup .= '</div>'; 1463 1464 1464 $row_actions = array( 1465 1465 'remove_data' => $remove_data_markup, … … 1502 1502 <span style="display:none" class="remove_personal_data_failed"><?php _e( 'Removing Data Failed!' ); ?> <a class="button" href="#" ><?php _e( 'Retry' ); ?></a></span> 1503 1503 <?php 1504 1505 echo '</div>'; 1504 1506 1505 1507 break; -
trunk/src/wp-admin/js/xfn.js
r42994 r43012 23 23 24 24 // Privacy request action handling 25 26 25 jQuery( document ).ready( function( $ ) { 27 26 var strings = window.privacyToolsL10n || {}; … … 40 39 function appendResultsAfterRow( $requestRow, classes, summaryMessage, additionalMessages ) { 41 40 clearResultsAfterRow( $requestRow ); 41 42 var itemList = ''; 42 43 if ( additionalMessages.length ) { 43 // TODO - render additionalMessages after the summaryMessage 44 $.each( additionalMessages, function( index, value ) { 45 itemList = itemList + '<li>' + value + '</li>'; 46 } ); 47 itemList = '<ul>' + itemList + '</ul>'; 44 48 } 45 49 46 50 $requestRow.after( function() { 47 return '<tr class="request-results"><td colspan="5"><div class="notice inline notice-alt ' + classes + '"><p>' + 48 summaryMessage + 49 '</p></div></td></tr>'; 51 return '<tr class="request-results"><td colspan="5">' + 52 '<div class="notice inline notice-alt ' + classes + '">' + 53 '<p>' + summaryMessage + '</p>' + 54 itemList + 55 '</div>' + 56 '</td>' + 57 '</tr>'; 50 58 } ); 51 59 } 60 61 $( '.export_personal_data a' ).click( function( event ) { 62 event.preventDefault(); 63 event.stopPropagation(); 64 65 var $this = $( this ); 66 var $action = $this.parents( '.export_personal_data' ); 67 var $requestRow = $this.parents( 'tr' ); 68 var requestID = $action.data( 'request-id' ); 69 var nonce = $action.data( 'nonce' ); 70 var exportersCount = $action.data( 'exporters-count' ); 71 var sendAsEmail = $action.data( 'send-as-email' ) ? true : false; 72 73 $action.blur(); 74 clearResultsAfterRow( $requestRow ); 75 76 function on_export_done_success( zipUrl ) { 77 set_action_state( $action, 'export_personal_data_success' ); 78 if ( 'undefined' !== typeof zipUrl ) { 79 window.location = zipUrl; 80 } else if ( ! sendAsEmail ) { 81 on_export_failure( strings.noExportFile ); 82 } 83 } 84 85 function on_export_failure( errorMessage ) { 86 set_action_state( $action, 'export_personal_data_failed' ); 87 if ( errorMessage ) { 88 appendResultsAfterRow( $requestRow, 'notice-error', strings.exportError, [ errorMessage ] ); 89 } 90 } 91 92 function do_next_export( exporterIndex, pageIndex ) { 93 $.ajax( 94 { 95 url: window.ajaxurl, 96 data: { 97 action: 'wp-privacy-export-personal-data', 98 exporter: exporterIndex, 99 id: requestID, 100 page: pageIndex, 101 security: nonce, 102 sendAsEmail: sendAsEmail 103 }, 104 method: 'post' 105 } 106 ).done( function( response ) { 107 if ( ! response.success ) { 108 // e.g. invalid request ID 109 on_export_failure( response.data ); 110 return; 111 } 112 var responseData = response.data; 113 if ( ! responseData.done ) { 114 setTimeout( do_next_export( exporterIndex, pageIndex + 1 ) ); 115 } else { 116 if ( exporterIndex < exportersCount ) { 117 setTimeout( do_next_export( exporterIndex + 1, 1 ) ); 118 } else { 119 on_export_done_success( responseData.url ); 120 } 121 } 122 } ).fail( function( jqxhr, textStatus, error ) { 123 // e.g. Nonce failure 124 on_export_failure( error ); 125 } ); 126 } 127 128 // And now, let's begin 129 set_action_state( $action, 'export_personal_data_processing' ); 130 do_next_export( 1, 1 ); 131 } ); 52 132 53 133 $( '.remove_personal_data a' ).click( function( event ) { … … 93 173 function on_erasure_failure() { 94 174 set_action_state( $action, 'remove_personal_data_failed' ); 95 appendResultsAfterRow( $requestRow, 'notice-error', strings. anErrorOccurred, [] );175 appendResultsAfterRow( $requestRow, 'notice-error', strings.removalError, [] ); 96 176 } 97 177 -
trunk/src/wp-includes/comment.php
r42994 r43012 3353 3353 case 'comment_link': 3354 3354 $value = get_comment_link( $comment->comment_ID ); 3355 $value = '<a href="' . $value . '" target="_blank" rel="noreferrer noopener">' . $value . '</a>'; 3355 3356 break; 3356 3357 } -
trunk/src/wp-includes/script-loader.php
r42986 r43012 716 716 'noneRemoved' => __( 'Personal data was found for this user but was not removed.' ), 717 717 'someNotRemoved' => __( 'Personal data was found for this user but some of the personal data found was not removed.' ), 718 'anErrorOccurred' => __( 'An error occurred while attempting to find and remove personal data.' ), 718 'removalError' => __( 'An error occurred while attempting to find and remove personal data.' ), 719 'noExportFile' => __( 'No personal data export file was generated.' ), 720 'exportError' => __( 'An error occurred while attempting to export personal data.' ), 719 721 ) 720 722 ); -
trunk/src/wp-includes/user.php
r43011 r43012 3146 3146 * 3147 3147 * @param int $request_id Request ID to get data about. 3148 * @return array|false3148 * @return WP_User_Request|false 3149 3149 */ 3150 3150 function wp_get_user_request_data( $request_id ) {
Note: See TracChangeset
for help on using the changeset viewer.