From c45b5d9fa91fe2d5d6d17de2231a6d4167e8292e Mon Sep 17 00:00:00 2001 From: David GABISON Date: Sun, 26 May 2024 22:07:09 +0200 Subject: [PATCH 01/14] fix: Windows compatibility --- composer.json | 5 +++-- tests/includes/legacy/tests-give.php | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d43fa2161e..05af62b001 100644 --- a/composer.json +++ b/composer.json @@ -46,8 +46,9 @@ "test": "./vendor/bin/phpunit --colors --stop-on-failure", "unreleased": "./vendor/bin/since-unreleased.sh", "strauss": [ - "test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.14.0/strauss.phar", - "vendor/stellarwp/validation/bin/set-domain domain=give", + "test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.19.1/strauss.phar", + "sed -i 's/PHP_EOL/\"\\n\"/' vendor/stellarwp/validation/bin/set-domain", + "@php vendor/stellarwp/validation/bin/set-domain domain=give", "@php bin/strauss.phar" ], "post-install-cmd": [ diff --git a/tests/includes/legacy/tests-give.php b/tests/includes/legacy/tests-give.php index c270de5229..8a7b5a5334 100644 --- a/tests/includes/legacy/tests-give.php +++ b/tests/includes/legacy/tests-give.php @@ -32,6 +32,8 @@ public function test_constants() { // Plugin Root File $path = str_replace( 'tests/unit-tests/', '', plugin_dir_path( $filePath ) ); + // Windows compatibility + $path = str_replace('/', DIRECTORY_SEPARATOR, $path); $this->assertSame( GIVE_PLUGIN_FILE, $path . 'give.php' ); } From 31632917ac7c74d1ceeb3d842d9507579309dd8d Mon Sep 17 00:00:00 2001 From: David GABISON Date: Sun, 10 Mar 2024 20:30:12 +0100 Subject: [PATCH 02/14] feat: allow third party plugin to add filters --- src/Views/Components/ListTable/Filters/index.tsx | 5 ++++- src/Views/Components/ListTable/ListTablePage/index.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Views/Components/ListTable/Filters/index.tsx b/src/Views/Components/ListTable/Filters/index.tsx index d1667f88df..925ffd0018 100644 --- a/src/Views/Components/ListTable/Filters/index.tsx +++ b/src/Views/Components/ListTable/Filters/index.tsx @@ -51,9 +51,12 @@ export const Filter = ({filter, value = null, onChange, debouncedOnChange}) => { }; // figure out what the initial filter state should be based on the filter configuration -export const getInitialFilterState = (filters) => { +export const getInitialFilterState = (filters, apiSettings) => { const state = {}; const urlParams = new URLSearchParams(window.location.search); + + // Allow third party extends filters + filters = wp.hooks.applyFilters(`give-${apiSettings.table.id}-list-table-filters`, filters); filters.map((filter) => { // if the search parameters contained a value for the filter, use that const filterQuery = decodeURI(urlParams.get(filter.name)); diff --git a/src/Views/Components/ListTable/ListTablePage/index.tsx b/src/Views/Components/ListTable/ListTablePage/index.tsx index e48a6a319a..49cdb66b7b 100644 --- a/src/Views/Components/ListTable/ListTablePage/index.tsx +++ b/src/Views/Components/ListTable/ListTablePage/index.tsx @@ -84,7 +84,7 @@ export default function ListTablePage({ }: ListTablePageProps) { const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(30); - const [filters, setFilters] = useState(getInitialFilterState(filterSettings)); + const [filters, setFilters] = useState(getInitialFilterState(filterSettings, apiSettings)); const [modalContent, setModalContent] = useState<{confirm; action; label; type?: 'normal' | 'warning' | 'danger'}>({ confirm: (selected) => {}, action: (selected) => {}, From 0d05d32306681dc34acdd821e0769a990ed889fd Mon Sep 17 00:00:00 2001 From: David GABISON Date: Mon, 5 Aug 2024 14:58:08 +0200 Subject: [PATCH 03/14] test: add test for ListDonation filtered by donor ID --- .../Donations/Endpoints/TestListDonations.php | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Donations/Endpoints/TestListDonations.php b/tests/Unit/Donations/Endpoints/TestListDonations.php index 064f46d2f2..fff4089092 100644 --- a/tests/Unit/Donations/Endpoints/TestListDonations.php +++ b/tests/Unit/Donations/Endpoints/TestListDonations.php @@ -33,10 +33,11 @@ public function testShouldReturnListWithSameSize() $mockRequest->set_param('testMode', give_is_test_mode()); $listDonations = give(ListDonations::class); + $expectedItems = $this->getMockColumns($donations); $response = $listDonations->handleRequest($mockRequest); - $this->assertSameSize($donations, $response->data['items']); + $this->assertSame($expectedItems, $response->data['items']); } /** @@ -58,7 +59,39 @@ public function testShouldReturnListWithSameData() $mockRequest->set_param('sortDirection', $sortDirection); $mockRequest->set_param('testMode', give_is_test_mode()); - $expectedItems = $this->getMockColumns($donations,$sortDirection); + $expectedItems = $this->getMockColumns($donations, $sortDirection); + + $listDonations = give(ListDonations::class); + + $response = $listDonations->handleRequest($mockRequest); + + $this->assertSame($expectedItems, $response->data['items']); + } + + /** + * @unreleased + * + * @return void + * @throws Exception + */ + public function testShouldReturnFilteredListByDonorId() + { + $donations = Donation::factory()->count(5)->create(); + $donorId = $donations[0]->donorId; + + $mockRequest = $this->getMockRequest(); + // set_params + $mockRequest->set_param('page', 1); + $mockRequest->set_param('perPage', 30); + $mockRequest->set_param('locale', 'us-US'); + $mockRequest->set_param('donor', (string)$donorId); + $mockRequest->set_param('testMode', give_is_test_mode()); + + $expectedItems = $this->getMockColumns( + array_filter($donations, function ($donation) use ($donorId) { + return $donation->donorId === $donorId; + }) + ); $listDonations = give(ListDonations::class); From c2bfff9affed7a4ba19fa84dc0bcbe813a246e1c Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 10:30:14 +0200 Subject: [PATCH 04/14] fix: strauss false positive --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 05af62b001..8d428a06d9 100644 --- a/composer.json +++ b/composer.json @@ -107,6 +107,11 @@ "symfony/deprecation-contracts" ] }, + "exclude_from_prefix": { + "namespaces": [ + "session" + ] + }, "delete_vendor_packages": true, "override_autoload": { "symfony/polyfill-ctype": {}, From b21997a645528bfcc2356665ea953330b79690b1 Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 12:34:31 +0200 Subject: [PATCH 05/14] refactor: add hook to allow adding api endpoint args --- src/Donations/Endpoints/ListDonations.php | 164 ++++++++++++---------- 1 file changed, 91 insertions(+), 73 deletions(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index 7645340d12..ecd5783e1c 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -23,14 +23,16 @@ class ListDonations extends Endpoint protected $endpoint = 'admin/donations'; /** + * @unreleased becomes public to be usable in hooks * @var WP_REST_Request */ - protected $request; + public $request; /** + * @unreleased becomes public to be usable in hooks * @var DonationsListTable */ - protected $listTable; + public $listTable; /** * @since 3.4.0 @@ -46,6 +48,77 @@ public function __construct(DonationsListTable $listTable) */ public function registerRoute() { + $args = [ + 'page' => [ + 'type' => 'integer', + 'required' => false, + 'default' => 1, + 'minimum' => 1 + ], + 'perPage' => [ + 'type' => 'integer', + 'required' => false, + 'default' => 30, + 'minimum' => 1 + ], + 'form' => [ + 'type' => 'integer', + 'required' => false, + 'default' => 0 + ], + 'search' => [ + 'type' => 'string', + 'required' => false, + 'sanitize_callback' => 'sanitize_text_field', + ], + 'start' => [ + 'type' => 'string', + 'required' => false, + 'validate_callback' => [$this, 'validateDate'] + ], + 'end' => [ + 'type' => 'string', + 'required' => false, + 'validate_callback' => [$this, 'validateDate'] + ], + 'donor' => [ + 'type' => 'string', + 'required' => false, + 'sanitize_callback' => 'sanitize_text_field', + ], + 'sortColumn' => [ + 'type' => 'string', + 'required' => false, + 'sanitize_callback' => 'sanitize_text_field', + ], + 'sortDirection' => [ + 'type' => 'string', + 'required' => false, + 'enum' => [ + 'asc', + 'desc', + ], + ], + 'locale' => [ + 'type' => 'string', + 'required' => false, + 'default' => get_locale(), + ], + 'testMode' => [ + 'type' => 'boolean', + 'required' => false, + 'default' => give_is_test_mode(), + ], + 'return' => [ + 'type' => 'string', + 'required' => false, + 'default' => 'columns', + 'enum' => [ + 'model', + 'columns', + ], + ], + ]; register_rest_route( 'give-api/v2', $this->endpoint, @@ -55,77 +128,22 @@ public function registerRoute() 'callback' => [$this, 'handleRequest'], 'permission_callback' => [$this, 'permissionsCheck'], ], - 'args' => [ - 'page' => [ - 'type' => 'integer', - 'required' => false, - 'default' => 1, - 'minimum' => 1 - ], - 'perPage' => [ - 'type' => 'integer', - 'required' => false, - 'default' => 30, - 'minimum' => 1 - ], - 'form' => [ - 'type' => 'integer', - 'required' => false, - 'default' => 0 - ], - 'search' => [ - 'type' => 'string', - 'required' => false, - 'sanitize_callback' => 'sanitize_text_field', - ], - 'start' => [ - 'type' => 'string', - 'required' => false, - 'validate_callback' => [$this, 'validateDate'] - ], - 'end' => [ - 'type' => 'string', - 'required' => false, - 'validate_callback' => [$this, 'validateDate'] - ], - 'donor' => [ - 'type' => 'string', - 'required' => false, - 'sanitize_callback' => 'sanitize_text_field', - ], - 'sortColumn' => [ - 'type' => 'string', - 'required' => false, - 'sanitize_callback' => 'sanitize_text_field', - ], - 'sortDirection' => [ - 'type' => 'string', - 'required' => false, - 'enum' => [ - 'asc', - 'desc', - ], - ], - 'locale' => [ - 'type' => 'string', - 'required' => false, - 'default' => get_locale(), - ], - 'testMode' => [ - 'type' => 'boolean', - 'required' => false, - 'default' => give_is_test_mode(), - ], - 'return' => [ - 'type' => 'string', - 'required' => false, - 'default' => 'columns', - 'enum' => [ - 'model', - 'columns', - ], - ], - ], + /** + * Allow adding API endpoint args + * + * @unreleased + * @param array $args Array of api args { + * Arg details + * + * @type string $type Type of value + * @type boolean $required Is this arg required for each request + * @type mixed $default Optional - Default value for this arg + * @type callable $validate_callback Optional + * @type callable $sanitize_callback Optional + * @type mixed[] $enum Optional - Array of allowed values + * }[] + */ + 'args' => apply_filters('give_list-donation_api_args', $args), ] ); } From b466d182f4d414b865fd4ab9aee733e27fd35efa Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 12:57:25 +0200 Subject: [PATCH 06/14] refactor: cleanly separate request blocks --- src/Donations/Endpoints/ListDonations.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index ecd5783e1c..1852a8c9fb 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -189,20 +189,22 @@ public function handleRequest(WP_REST_Request $request): WP_REST_Response */ public function getDonations(): array { + $query = give()->donations->prepareQuery(); + + // Pagination $page = $this->request->get_param('page'); $perPage = $this->request->get_param('perPage'); + $query->limit($perPage)->offset(($page - 1) * $perPage); + + // Sort $sortColumns = $this->listTable->getSortColumnById($this->request->get_param('sortColumn') ?: 'id'); $sortDirection = $this->request->get_param('sortDirection') ?: 'desc'; - - $query = give()->donations->prepareQuery(); - list($query) = $this->getWhereConditions($query); - foreach ($sortColumns as $sortColumn) { $query->orderBy($sortColumn, $sortDirection); } - $query->limit($perPage) - ->offset(($page - 1) * $perPage); + // Where + list($query) = $this->getWhereConditions($query); $donations = $query->getAll(); From 30071abe18be2585cd42cc4f851b8297d10a06c8 Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:11:31 +0200 Subject: [PATCH 07/14] refactor: factorize where conditions : testMode use parentheses on OR WHERE clause --- src/Donations/Endpoints/ListDonations.php | 35 +++++++++++------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index 1852a8c9fb..df12d779e5 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -223,9 +223,7 @@ public function getDonations(): array */ public function getTotalDonationsCount(): int { - $query = DB::table('posts') - ->where('post_type', 'give_payment') - ->groupBy('mode'); + $query = DB::table('posts')->where('post_type', 'give_payment'); list($query, $dependencies) = $this->getWhereConditions($query); @@ -256,13 +254,9 @@ protected function getWhereConditions(QueryBuilder $query): array $end = $this->request->get_param('end'); $form = $this->request->get_param('form'); $donor = $this->request->get_param('donor'); - $testMode = $this->request->get_param('testMode'); - - $dependencies = [ - DonationMetaKeys::MODE(), - ]; + $dependencies = []; + list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); - $hasWhereConditions = $search || $start || $end || $form || $donor; if ($search) { if (ctype_digit($search)) { @@ -307,19 +301,22 @@ protected function getWhereConditions(QueryBuilder $query): array } elseif ($end) { $query->where('post_date', $end, '<='); } + return [$query, $dependencies]; + } - if ($hasWhereConditions) { - $query->havingRaw('HAVING COALESCE(give_donationmeta_attach_meta_mode.meta_value, %s) = %s', DonationMode::LIVE, $testMode ? DonationMode::TEST : DonationMode::LIVE); - } elseif ($testMode) { + private function getModeWhereCondition (QueryBuilder $query, array $dependencies) + { + $dependencies[] = DonationMetaKeys::MODE(); + $testMode = $this->request->get_param('testMode'); + if ($testMode) { $query->where('give_donationmeta_attach_meta_mode.meta_value', DonationMode::TEST); } else { - $query->whereIsNull('give_donationmeta_attach_meta_mode.meta_value') - ->orWhere('give_donationmeta_attach_meta_mode.meta_value', DonationMode::TEST, '<>'); + $query->where(function ($whereBuilder) { + $whereBuilder + ->whereIsNull('give_donationmeta_attach_meta_mode.meta_value') + ->orWhere('give_donationmeta_attach_meta_mode.meta_value', DonationMode::TEST, '<>'); + }); } - - return [ - $query, - $dependencies, - ]; + return [$query, $dependencies]; } } From e59087c6ad009fda9790e97d2fbad757c74299bb Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:18:09 +0200 Subject: [PATCH 08/14] refactor: factorize where conditions : date --- src/Donations/Endpoints/ListDonations.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index df12d779e5..66ba6413de 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -250,11 +250,10 @@ public function getTotalDonationsCount(): int protected function getWhereConditions(QueryBuilder $query): array { $search = $this->request->get_param('search'); - $start = $this->request->get_param('start'); - $end = $this->request->get_param('end'); $form = $this->request->get_param('form'); $donor = $this->request->get_param('donor'); $dependencies = []; + list($query, $dependencies) = $this->getDateWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); @@ -293,7 +292,13 @@ protected function getWhereConditions(QueryBuilder $query): array ->where('give_donationmeta_attach_meta_formId.meta_value', $form); $dependencies[] = DonationMetaKeys::FORM_ID(); } + return [$query, $dependencies]; + } + private function getDateWhereCondition (QueryBuilder $query, array $dependencies) + { + $start = $this->request->get_param('start'); + $end = $this->request->get_param('end'); if ($start && $end) { $query->whereBetween('post_date', $start, $end); } elseif ($start) { From 3cdc55d16f714feefe75caeb1845d0cb5cca73f5 Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:19:41 +0200 Subject: [PATCH 09/14] refactor: factorize where conditions : form --- src/Donations/Endpoints/ListDonations.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index 66ba6413de..dd3d05ed60 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -250,9 +250,9 @@ public function getTotalDonationsCount(): int protected function getWhereConditions(QueryBuilder $query): array { $search = $this->request->get_param('search'); - $form = $this->request->get_param('form'); $donor = $this->request->get_param('donor'); $dependencies = []; + list($query, $dependencies) = $this->getFormWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getDateWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); @@ -286,7 +286,12 @@ protected function getWhereConditions(QueryBuilder $query): array $dependencies[] = DonationMetaKeys::LAST_NAME(); } } + return [$query, $dependencies]; + } + private function getFormWhereCondition (QueryBuilder $query, array $dependencies) + { + $form = $this->request->get_param('form'); if ($form) { $query ->where('give_donationmeta_attach_meta_formId.meta_value', $form); From 118979103c2fc785ea025dcd37cc8f89c0b9fbff Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:20:16 +0200 Subject: [PATCH 10/14] refactor: factorize where conditions : donor --- src/Donations/Endpoints/ListDonations.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index dd3d05ed60..548187cbb2 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -250,8 +250,8 @@ public function getTotalDonationsCount(): int protected function getWhereConditions(QueryBuilder $query): array { $search = $this->request->get_param('search'); - $donor = $this->request->get_param('donor'); $dependencies = []; + list($query, $dependencies) = $this->getDonorWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getFormWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getDateWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); @@ -272,7 +272,12 @@ protected function getWhereConditions(QueryBuilder $query): array $dependencies[] = DonationMetaKeys::LAST_NAME(); } } + return [$query, $dependencies]; + } + private function getDonorWhereCondition (QueryBuilder $query, array $dependencies) + { + $donor = $this->request->get_param('donor'); if ($donor) { if (ctype_digit($donor)) { $query From 513841cbb1f529d4f28537b21557f5389e7a197b Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:20:56 +0200 Subject: [PATCH 11/14] refactor: factorize where conditions : search --- src/Donations/Endpoints/ListDonations.php | 34 +++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index 548187cbb2..c913f05a02 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -249,28 +249,32 @@ public function getTotalDonationsCount(): int */ protected function getWhereConditions(QueryBuilder $query): array { - $search = $this->request->get_param('search'); $dependencies = []; + list($query, $dependencies) = $this->getSearchWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getDonorWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getFormWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getDateWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); + return [$query, $dependencies]; + } - if ($search) { - if (ctype_digit($search)) { - $query->where('id', $search); - } elseif (strpos($search, '@') !== false) { - $query - ->whereLike('give_donationmeta_attach_meta_email.meta_value', $search); - $dependencies[] = DonationMetaKeys::EMAIL(); - } else { - $query - ->whereLike('give_donationmeta_attach_meta_firstName.meta_value', $search) - ->orWhereLike('give_donationmeta_attach_meta_lastName.meta_value', $search); - $dependencies[] = DonationMetaKeys::FIRST_NAME(); - $dependencies[] = DonationMetaKeys::LAST_NAME(); - } + private function getSearchWhereCondition (QueryBuilder $query, array $dependencies) + { + $search = $this->request->get_param('search'); + if (!$search) return [$query, $dependencies]; + if (ctype_digit($search)) { + $query->where('id', $search); + } elseif (strpos($search, '@') !== false) { + $query + ->whereLike('give_donationmeta_attach_meta_email.meta_value', $search); + $dependencies[] = DonationMetaKeys::EMAIL(); + } else { + $query + ->whereLike('give_donationmeta_attach_meta_firstName.meta_value', $search) + ->orWhereLike('give_donationmeta_attach_meta_lastName.meta_value', $search); + $dependencies[] = DonationMetaKeys::FIRST_NAME(); + $dependencies[] = DonationMetaKeys::LAST_NAME(); } return [$query, $dependencies]; } From 3cc566bc7bf921cffa4852a031bbbcf0f2277d5e Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:26:55 +0200 Subject: [PATCH 12/14] refactor: add hook to allow adding query request clauses --- src/Donations/Endpoints/ListDonations.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index c913f05a02..f6b776c88a 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -256,7 +256,17 @@ protected function getWhereConditions(QueryBuilder $query): array list($query, $dependencies) = $this->getDateWhereCondition($query, $dependencies); list($query, $dependencies) = $this->getModeWhereCondition($query, $dependencies); - return [$query, $dependencies]; + /** + * Allow adding request clauses + * + * @unreleased + * @param array $value { + * @type ModelQueryBuilder $query Donation query builder + * @type DonationMetaKeys[] $dependencies List of meta dependencies for added where clauses + * } + * @param ListDonations $endpoint API Endpoint instance + */ + return apply_filters('give_list-donation_where_conditions', [$query, $dependencies], $this); } private function getSearchWhereCondition (QueryBuilder $query, array $dependencies) From eeac8232916d12c0532bfc9ac1681307a311c869 Mon Sep 17 00:00:00 2001 From: David GABISON Date: Fri, 9 Aug 2024 13:52:52 +0200 Subject: [PATCH 13/14] test: add test for ListDonations custom filter --- .../Donations/Endpoints/TestListDonations.php | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/Unit/Donations/Endpoints/TestListDonations.php b/tests/Unit/Donations/Endpoints/TestListDonations.php index fff4089092..b6c96cd764 100644 --- a/tests/Unit/Donations/Endpoints/TestListDonations.php +++ b/tests/Unit/Donations/Endpoints/TestListDonations.php @@ -100,6 +100,63 @@ public function testShouldReturnFilteredListByDonorId() $this->assertSame($expectedItems, $response->data['items']); } + /** + * @unreleased + * + * @return void + * @throws Exception + */ + public function testShouldAllowAddingFilters() + { + $donations = Donation::factory()->count(5)->create(); + + $expectedItems = array_slice($donations, 0, 2); + foreach ($expectedItems as $item) { + give_update_payment_meta($item->id, 'my_key', 'on'); + } + $expectedItems = $this->getMockColumns($expectedItems); + + add_filter('give_list-donation_api_args', function ($args) { + $args['my_param'] = [ + 'type' => 'string', + 'required' => false, + 'sanitize_callback' => 'sanitize_text_field', + ]; + return $args; + }); + + add_filter('give_list-donation_where_conditions', function ($value, $endpoint) { + list($query, $dependencies) = $value; + + $paramValue = $endpoint->request->get_param('my_param'); + if (!empty($paramValue)) { + $query->attachMeta( + 'give_donationmeta', + 'ID', + 'donation_id', + ['my_key', 'myKey'] + ); + $query->where('give_donationmeta_attach_meta_myKey.meta_value', $paramValue); + } + + return [$query, $dependencies]; + }, 10, 2); + + $mockRequest = $this->getMockRequest(); + // set_params + $mockRequest->set_param('page', 1); + $mockRequest->set_param('perPage', 30); + $mockRequest->set_param('locale', 'us-US'); + $mockRequest->set_param('testMode', give_is_test_mode()); + $mockRequest->set_param('my_param', 'on'); + + $listDonations = give(ListDonations::class); + + $response = $listDonations->handleRequest($mockRequest); + + $this->assertSame($expectedItems, $response->data['items']); + } + /** * * @since 2.25.0 From 55eb0f93c5be5aeabc835062c149ea51fead7903 Mon Sep 17 00:00:00 2001 From: David GABISON Date: Sun, 8 Sep 2024 23:36:13 +0200 Subject: [PATCH 14/14] fix: database error when $dependencies contains the same value twice --- src/Donations/Endpoints/ListDonations.php | 1 + .../Donations/Endpoints/TestListDonations.php | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Donations/Endpoints/ListDonations.php b/src/Donations/Endpoints/ListDonations.php index f6b776c88a..5d77942111 100644 --- a/src/Donations/Endpoints/ListDonations.php +++ b/src/Donations/Endpoints/ListDonations.php @@ -227,6 +227,7 @@ public function getTotalDonationsCount(): int list($query, $dependencies) = $this->getWhereConditions($query); + $dependencies = array_unique($dependencies); $query->attachMeta( 'give_donationmeta', 'ID', diff --git a/tests/Unit/Donations/Endpoints/TestListDonations.php b/tests/Unit/Donations/Endpoints/TestListDonations.php index b6c96cd764..6f43b5eb92 100644 --- a/tests/Unit/Donations/Endpoints/TestListDonations.php +++ b/tests/Unit/Donations/Endpoints/TestListDonations.php @@ -157,6 +157,38 @@ public function testShouldAllowAddingFilters() $this->assertSame($expectedItems, $response->data['items']); } + /** + * @unreleased + * + * @return void + * @throws Exception + */ + public function testShouldAllowUsingDependencyTwice() + { + $donations = Donation::factory()->count(5)->create(); + + $firstName = $donations[3]->firstName; + $expectedItems = array_filter($donations, function ($donation) use ($firstName) { + return $donation->firstName == $firstName; + }); + $expectedItems = $this->getMockColumns($expectedItems); + + $mockRequest = $this->getMockRequest(); + // set_params + $mockRequest->set_param('page', 1); + $mockRequest->set_param('perPage', 30); + $mockRequest->set_param('locale', 'us-US'); + $mockRequest->set_param('testMode', give_is_test_mode()); + $mockRequest->set_param('donor', $firstName); + $mockRequest->set_param('search', $firstName); + + $listDonations = give(ListDonations::class); + + $response = $listDonations->handleRequest($mockRequest); + + $this->assertSame($expectedItems, $response->data['items']); + } + /** * * @since 2.25.0