Skip to content

Commit

Permalink
Fix customer filters and download user filtering (woocommerce#1618)
Browse files Browse the repository at this point in the history
* Add the ability to search name, username, and email fields on the customer endpoint, update autocompletors, add in include parameter.

* Update the username to be returned in the download response, update download filtering based on customer id, and only rename include parameter on main customers endpoint.
  • Loading branch information
justinshreve authored Feb 19, 2019
1 parent 8e9a988 commit 488bfa9
Show file tree
Hide file tree
Showing 15 changed files with 313 additions and 35 deletions.
2 changes: 1 addition & 1 deletion client/analytics/report/downloads/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const advancedFilters = {
getLabels: getProductLabels,
},
},
user: {
customer: {
labels: {
add: __( 'Username', 'wc-admin' ),
placeholder: __( 'Search customer username', 'wc-admin' ),
Expand Down
16 changes: 12 additions & 4 deletions client/analytics/report/downloads/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,17 @@ export default class CouponsReportTable extends Component {
const persistedQuery = getPersistedQuery( query );

return map( downloads, download => {
const { _embedded, date, file_name, file_path, ip_address, order_id, product_id } = download;
const {
_embedded,
date,
file_name,
file_path,
ip_address,
order_id,
product_id,
username,
} = download;
const { name: productName } = _embedded.product[ 0 ];
const { name: userName } = _embedded.user[ 0 ];

const productLink = getNewPath( persistedQuery, 'products', {
filter: 'single_product',
Expand Down Expand Up @@ -109,8 +117,8 @@ export default class CouponsReportTable extends Component {
value: order_id,
},
{
display: userName,
value: userName,
display: username,
value: username,
},
{
display: ip_address,
Expand Down
24 changes: 24 additions & 0 deletions includes/api/class-wc-admin-rest-customers-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,28 @@ class WC_Admin_REST_Customers_Controller extends WC_Admin_REST_Reports_Customers
* @var string
*/
protected $rest_base = 'customers';

/**
* Maps query arguments from the REST request.
*
* @param array $request Request array.
* @return array
*/
protected function prepare_reports_query( $request ) {
$args = parent::prepare_reports_query( $request );
$args['customers'] = $request['include'];
return $args;
}

/**
* Get the query params for collections.
*
* @return array
*/
public function get_collection_params() {
$params = parent::get_collection_params();
$params['include'] = $params['customers'];
unset( $params['customers'] );
return $params;
}
}
14 changes: 12 additions & 2 deletions includes/api/class-wc-admin-rest-reports-customers-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ protected function prepare_reports_query( $request ) {
$args['orderby'] = $request['orderby'];
$args['match'] = $request['match'];
$args['search'] = $request['search'];
$args['searchby'] = $request['searchby'];
$args['username'] = $request['username'];
$args['email'] = $request['email'];
$args['country'] = $request['country'];
Expand Down Expand Up @@ -335,10 +336,20 @@ public function get_collection_params() {
'validate_callback' => 'rest_validate_request_arg',
);
$params['search'] = array(
'description' => __( 'Limit response to objects with a customer name containing the search term.', 'wc-admin' ),
'description' => __( 'Limit response to objects with a customer field containing the search term. Searches the field provided by `searchby`.', 'wc-admin' ),
'type' => 'string',
'validate_callback' => 'rest_validate_request_arg',
);
$params['searchby'] = array(
'description' => 'Limit results with `search` and `searchby` to specific fields containing the search term.',
'type' => 'string',
'default' => 'name',
'enum' => array(
'name',
'username',
'email',
),
);
$params['username'] = array(
'description' => __( 'Limit response to objects with a specfic username.', 'wc-admin' ),
'type' => 'string',
Expand Down Expand Up @@ -455,7 +466,6 @@ public function get_collection_params() {
'items' => array(
'type' => 'integer',
),

);

return $params;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,20 @@ public function get_collection_params() {
'validate_callback' => 'rest_validate_request_arg',
);
$params['search'] = array(
'description' => __( 'Limit response to objects with a specfic customer name.', 'wc-admin' ),
'description' => __( 'Limit response to objects with a customer field containing the search term. Searches the field provided by `searchby`.', 'wc-admin' ),
'type' => 'string',
'validate_callback' => 'rest_validate_request_arg',
);
$params['searchby'] = array(
'description' => 'Limit results with `search` and `searchby` to specific fields containing the search term.',
'type' => 'string',
'default' => 'name',
'enum' => array(
'name',
'username',
'email',
),
);
$params['username'] = array(
'description' => __( 'Limit response to objects with a specfic username.', 'wc-admin' ),
'type' => 'string',
Expand Down Expand Up @@ -309,15 +319,14 @@ public function get_collection_params() {
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['customers'] = array(
$params['customers'] = array(
'description' => __( 'Limit result to items with specified customer ids.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'type' => 'integer',
),

);

return $params;
Expand Down
17 changes: 10 additions & 7 deletions includes/api/class-wc-admin-rest-reports-downloads-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class WC_Admin_REST_Reports_Downloads_Controller extends WC_REST_Reports_Control
* Get items.
*
* @param WP_REST_Request $request Request data.
*
* @return array|WP_Error
*/
public function get_items( $request ) {
Expand Down Expand Up @@ -111,6 +110,8 @@ public function prepare_item_for_response( $report, $request ) {
$filename = basename( $file_path );
$response->data['file_name'] = apply_filters( 'woocommerce_file_download_filename', $filename, $product_id );
$response->data['file_path'] = $file_path;
$customer = new WC_Customer( $data['user_id'] );
$response->data['username'] = $customer->get_username();

/**
* Filter a report returned from the API.
Expand All @@ -136,10 +137,6 @@ protected function prepare_links( $object ) {
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, 'products', $object['product_id'] ) ),
'embeddable' => true,
),
'user' => array(
'href' => rest_url( 'wp/v2/users/' . $object['user_id'] ),
'embeddable' => true,
),
);

return $links;
Expand Down Expand Up @@ -216,6 +213,12 @@ public function get_item_schema() {
'context' => array( 'view', 'edit' ),
'description' => __( 'User ID for the downloader.', 'wc-admin' ),
),
'username' => array(
'type' => 'string',
'readonly' => true,
'context' => array( 'view', 'edit' ),
'description' => __( 'User name of the downloader.', 'wc-admin' ),
),
'ip_address' => array(
'type' => 'string',
'readonly' => true,
Expand Down Expand Up @@ -330,7 +333,7 @@ public function get_collection_params() {
'type' => 'integer',
),
);
$params['user_includes'] = array(
$params['customer_includes'] = array(
'description' => __( 'Limit response to objects that have the specified user ids.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
Expand All @@ -339,7 +342,7 @@ public function get_collection_params() {
'type' => 'integer',
),
);
$params['user_excludes'] = array(
$params['customer_excludes'] = array(
'description' => __( 'Limit response to objects that don\'t have the specified user ids.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ protected function prepare_reports_query( $request ) {
$args['match'] = $request['match'];
$args['product_includes'] = (array) $request['product_includes'];
$args['product_excludes'] = (array) $request['product_excludes'];
$args['customer_includes'] = (array) $request['customer_includes'];
$args['customer_excludes'] = (array) $request['customer_excludes'];
$args['order_includes'] = (array) $request['order_includes'];
$args['order_excludes'] = (array) $request['order_excludes'];
$args['ip_address_includes'] = (array) $request['ip_address_includes'];
Expand Down Expand Up @@ -329,17 +331,17 @@ public function get_collection_params() {
'type' => 'integer',
),
);
$params['user_includes'] = array(
'description' => __( 'Limit response to objects that have the specified user ids.', 'wc-admin' ),
$params['customer_includes'] = array(
'description' => __( 'Limit response to objects that have the specified customer ids.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'type' => 'integer',
),
);
$params['user_excludes'] = array(
'description' => __( 'Limit response to objects that don\'t have the specified user ids.', 'wc-admin' ),
$params['customer_excludes'] = array(
'description' => __( 'Limit response to objects that don\'t have the specified customer ids.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,22 @@ protected function get_sql_query_params( $query_args ) {
}
}

$search_params = array(
'name',
'username',
'email',
);

if ( ! empty( $query_args['search'] ) ) {
$name_like = '%' . $wpdb->esc_like( $query_args['search'] ) . '%';
$where_clauses[] = $wpdb->prepare( "CONCAT_WS( ' ', first_name, last_name ) LIKE %s", $name_like );

if ( empty( $query_args['searchby'] ) || 'name' === $query_args['searchby'] || ! in_array( $query_args['searchby'], $search_params ) ) {
$searchby = "CONCAT_WS( ' ', first_name, last_name )";
} else {
$searchby = $query_args['searchby'];
}

$where_clauses[] = $wpdb->prepare( "{$searchby} LIKE %s", $name_like ); // WPCS: unprepared SQL ok.
}

// Allow a list of customer IDs to be specified.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,32 @@ protected function get_sql_query_params( $query_args ) {
)";
}

$included_users = $this->get_included_users( $query_args );
$excluded_users = $this->get_excluded_users( $query_args );
if ( $included_users ) {
$customer_lookup_table = $wpdb->prefix . 'wc_customer_lookup';
$included_customers = $this->get_included_customers( $query_args );
$excluded_customers = $this->get_excluded_customers( $query_args );
if ( $included_customers ) {
$where_filters[] = " {$lookup_table}.permission_id IN (
SELECT
DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id
FROM
{$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE
{$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN ({$included_users})
{$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN (
SELECT {$customer_lookup_table}.user_id FROM {$customer_lookup_table} WHERE {$customer_lookup_table}.customer_id IN ({$included_customers})
)
)";
}

if ( $excluded_users ) {
if ( $excluded_customers ) {
$where_filters[] = " {$lookup_table}.permission_id NOT IN (
SELECT
DISTINCT {$wpdb->prefix}woocommerce_downloadable_product_permissions.permission_id
FROM
{$wpdb->prefix}woocommerce_downloadable_product_permissions
WHERE
{$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN ({$excluded_users})
{$wpdb->prefix}woocommerce_downloadable_product_permissions.user_id IN (
SELECT {$customer_lookup_table}.user_id FROM {$customer_lookup_table} WHERE {$customer_lookup_table}.customer_id IN ({$excluded_customers})
)
)";
}

Expand Down Expand Up @@ -205,6 +210,35 @@ protected function get_excluded_ip_addresses( $query_args ) {
return $excluded_ips_str;
}

/**
* Returns comma separated ids of included customers, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_included_customers( $query_args ) {
$included_customers_str = '';

if ( isset( $query_args['customer_includes'] ) && is_array( $query_args['customer_includes'] ) && count( $query_args['customer_includes'] ) > 0 ) {
$included_customers_str = implode( ',', $query_args['customer_includes'] );
}
return $included_customers_str;
}

/**
* Returns comma separated ids of excluded customers, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_excluded_customers( $query_args ) {
$excluded_customer_str = '';

if ( isset( $query_args['customer_excludes'] ) && is_array( $query_args['customer_excludes'] ) && count( $query_args['customer_excludes'] ) > 0 ) {
$excluded_customer_str = implode( ',', $query_args['customer_excludes'] );
}
return $excluded_customer_str;
}

/**
* Fills WHERE clause of SQL request with date-related constraints.
Expand Down
1 change: 1 addition & 0 deletions packages/components/src/search/autocompleters/customers.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default {
if ( name ) {
const query = {
search: name,
searchby: 'name',
per_page: 10,
};
payload = stringifyQuery( query );
Expand Down
3 changes: 2 additions & 1 deletion packages/components/src/search/autocompleters/emails.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default {
let payload = '';
if ( search ) {
const query = {
email: search,
search,
searchby: 'email',
per_page: 10,
};
payload = stringifyQuery( query );
Expand Down
3 changes: 2 additions & 1 deletion packages/components/src/search/autocompleters/usernames.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default {
let payload = '';
if ( search ) {
const query = {
username: search,
search,
searchby: 'username',
per_page: 10,
};
payload = stringifyQuery( query );
Expand Down
Loading

0 comments on commit 488bfa9

Please sign in to comment.