Skip to content
Snippets Groups Projects
Commit 0d3d2a6f authored by Thomas Seidl's avatar Thomas Seidl
Browse files

Issue #2972305 by drunken monkey: Fixed missing access checks in NewResultsCheck::checkAll().

parent f0ef14e3
No related branches found
No related tags found
1 merge request!11Check access in NewResultsCheck::checkAll()
Pipeline #103355 canceled
Search API Saved Searches 1.x, dev (xxxx-xx-xx):
------------------------------------------------
- #2972305 by drunken monkey: Fixed missing access checks in
NewResultsCheck::checkAll().
- #3419306 by drunken monkey: Increased Drupal core version requirement to 10.1.
- #3422224 by drunken monkey: Enabled GitLab CI.
- #3330345 by drunken monkey, khiminrm: Fixed errors when "E-Mail" notification
......
......@@ -20,6 +20,7 @@ use Drupal\Core\Utility\Error;
use Drupal\search_api\IndexInterface;
use Drupal\search_api_saved_searches\Entity\SavedSearch;
use Drupal\search_api_saved_searches\Entity\SavedSearchAccessControlHandler;
use Drupal\search_api_saved_searches\Entity\SavedSearchType;
use Drupal\search_api_saved_searches\Plugin\search_api_saved_searches\notification\Email;
use Drupal\search_api_saved_searches\SavedSearchesException;
use Drupal\user\UserInterface;
......@@ -146,6 +147,18 @@ function search_api_saved_searches_user_update(UserInterface $account): void {
_search_api_saved_searches_deactivate_searches($account);
}
// Same if they lose permission to use saved searches (of a specific type).
$types = [];
foreach (SavedSearchType::loadMultiple() as $type_id => $type) {
$perm = "use $type_id search_api_saved_searches";
if ($original->hasPermission($perm) && !$account->hasPermission($perm)) {
$types[] = $type_id;
}
}
if ($types) {
_search_api_saved_searches_deactivate_searches($account, $types);
}
// Forward the hook invocation to the "E-mail" notification plugin.
Email::onUserUpdate($account, $original);
}
......@@ -184,10 +197,15 @@ function _search_api_saved_searches_claim_anonymous_searches(UserInterface $acco
*
* @param \Drupal\user\UserInterface $account
* The user account in question.
* @param string[]|null $type_ids
* (optional) If given, only deactivate saved searches of those types.
*/
function _search_api_saved_searches_deactivate_searches(UserInterface $account): void {
function _search_api_saved_searches_deactivate_searches(UserInterface $account, ?array $type_ids = NULL): void {
$searches = _search_api_saved_searches_load_searches($account->id());
foreach ($searches as $search) {
if ($type_ids !== NULL && !in_array($search->bundle(), $type_ids)) {
continue;
}
$search->set('notify_interval', -1);
try {
$search->save();
......
......@@ -105,6 +105,18 @@ class NewResultsCheck {
foreach ($searches as $search) {
try {
// Make sure the search is enabled and the owner still has permission to
// use saved searches of this type.
if (!$search->get('status')->value
|| $search->get('notify_interval')->value < 0) {
continue;
}
$permission = "use {$search->bundle()} search_api_saved_searches";
if (!$search->getOwner()?->hasPermission($permission)) {
$search->set('notify_interval', -1);
$search->save();
continue;
}
$results = $this->getNewResults($search);
$search->set('last_executed', $now);
$search->save();
......
......@@ -18,6 +18,7 @@ use Drupal\search_api_test\PluginTestTrait;
use Drupal\Tests\search_api\Kernel\TestLogger;
use Drupal\Tests\search_api\Kernel\TestTimeService;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
......@@ -81,6 +82,9 @@ class EmailTranslationTest extends KernelTestBase {
'search_api_saved_searches',
'user',
]);
$permission = 'use default search_api_saved_searches';
$this->grantPermissions(Role::load(Role::ANONYMOUS_ID), [$permission]);
$this->grantPermissions(Role::load(Role::AUTHENTICATED_ID), [$permission]);
// Create a second language and sets up session parameter-based language
// negotiation, so we can more easily switch.
......@@ -224,7 +228,7 @@ class EmailTranslationTest extends KernelTestBase {
// Retrieve the sent activation mail and check the language it used.
$this->container->get('search_api_saved_searches.email_queue')->destruct();
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$captured_emails = \Drupal::state()->get('system.test_mail_collector', []);
\Drupal::state()->delete('system.test_mail_collector');
$this->assertCount(1, $captured_emails);
$activation_mail = reset($captured_emails);
......@@ -246,7 +250,7 @@ class EmailTranslationTest extends KernelTestBase {
// Retrieve the sent notification mail and check the language it used.
$this->container->get('search_api_saved_searches.email_queue')->destruct();
$captured_emails = \Drupal::state()->get('system.test_mail_collector');
$captured_emails = \Drupal::state()->get('system.test_mail_collector', []);
\Drupal::state()->delete('system.test_mail_collector');
$this->assertCount(1, $captured_emails);
$notification_mail = reset($captured_emails);
......
......@@ -8,6 +8,7 @@ use Drupal\search_api\Entity\Index;
use Drupal\search_api_saved_searches\Entity\SavedSearch;
use Drupal\search_api_saved_searches\Entity\SavedSearchType;
use Drupal\Tests\search_api\Kernel\TestLogger;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;
......@@ -60,12 +61,28 @@ class UserCrudReactionTest extends KernelTestBase {
'name' => '',
'status' => FALSE,
])->save();
// Create the anonymous role and a test role and grant the permission to
// create saved searches to both of them.
$permission = 'use default search_api_saved_searches';
Role::create([
'id' => Role::ANONYMOUS_ID,
'label' => 'Anonymous user',
'permissions' => [$permission],
])->save();
Role::create([
'id' => 'test_role',
'label' => 'Test role',
'permissions' => [$permission],
])->save();
// Add a test user that will become the owner of our saved searches.
$this->testUser = User::create([
'uid' => 5,
'name' => 'test',
'status' => TRUE,
'mail' => 'test@example.com',
'roles' => ['test_role'],
]);
$this->testUser->save();
......@@ -234,6 +251,63 @@ class UserCrudReactionTest extends KernelTestBase {
}
}
/**
* Verifies correct reaction to a user account losing a role.
*
* @see search_api_saved_searches_user_update()
* @see _search_api_saved_searches_deactivate_searches()
*/
public function testUserLoseRole() {
// Remove the test role from our test user.
$this->testUser->removeRole('test_role');
$this->testUser->save();
// Make sure this disabled the saved search.
$this->reloadSavedSearches();
$search = array_shift($this->savedSearches);
$this->assertEquals(-1, $search->get('notify_interval')->value);
// Verify that the other alerts were unaffected.
foreach ($this->savedSearches as $search) {
$this->assertEquals(3600 * 24, $search->get('notify_interval')->value);
}
}
/**
* Verifies correct reaction to a role losing a permission.
*
* This cannot be (easily) handled by a hook so we instead check for this when
* checking alerts for new results.
*
* @see \Drupal\search_api_saved_searches\Service\NewResultsCheck::checkAll()
*/
public function testRoleLosePermission() {
// Remove the permission to saved searches from our test role.
$role = Role::load('test_role');
$role->revokePermission('use default search_api_saved_searches');
$role->save();
// Make sure the test search will be picked up by the new results check. The
// "next_execution" field is automatically re-computed when saving a search,
// so we need to do this by changing the "last_executed" field to something
// more than a day ago.
$search = reset($this->savedSearches);
$time = \Drupal::time()->getRequestTime();
$search->set('last_executed', $time - 86400 - 10);
$search->save();
$this->reloadSavedSearches();
$search = reset($this->savedSearches);
$this->assertLessThan($time, $search->get('next_execution')->value);
// Do a "new results" check.
\Drupal::getContainer()->get('search_api_saved_searches.new_results_check')
->checkAll();
// Make sure the saved search was disabled.
$this->reloadSavedSearches();
$search = reset($this->savedSearches);
$this->assertEquals(-1, $search->get('notify_interval')->value);
}
/**
* Verifies correct reaction to the deletion of a user account.
*
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment