From 4da5646ad382962ed6ccb77e9139c9be898abee0 Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Thu, 8 Jan 2026 14:45:03 +0100 Subject: [PATCH 1/5] Added a coomand for checking if user email exist in api and MW db --- .../Commands/User/CheckUserEmailExist.php | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 app/Console/Commands/User/CheckUserEmailExist.php diff --git a/app/Console/Commands/User/CheckUserEmailExist.php b/app/Console/Commands/User/CheckUserEmailExist.php new file mode 100644 index 00000000..ffbfc5cc --- /dev/null +++ b/app/Console/Commands/User/CheckUserEmailExist.php @@ -0,0 +1,76 @@ +argument('emails'); + + $manager = app()->db; + $manager->purge('mw'); + $mwConn = $manager->connection('mw'); + $pdo = $mwConn->getPdo(); + + $dbStmt = $pdo->query("SHOW DATABASES LIKE 'mwdb_%'"); + $mwDatabases = $dbStmt->fetchAll(PDO::FETCH_COLUMN); + + foreach ($emails as $email) { + $found = false; + + //Check apidb.users + if (User::whereEmail($email)->exists()) { + $this->line("FOUND: {$email} in apidb.users"); + $found = true; + } + + //Check MediaWiki databases + foreach ($mwDatabases as $dbName) { + //fetch user table name + $tableStmt = $pdo->prepare(" + SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = :db + AND TABLE_NAME LIKE '%\_user' + LIMIT 1 + "); + $tableStmt->execute(['db' => $dbName]); + $userTable = $tableStmt->fetchColumn(); + if (!$userTable) { + continue; + } + + $query = " + SELECT user_id + FROM {$dbName}.{$userTable} + WHERE user_email = :email + LIMIT 1 + "; + + $emailStmt = $pdo->prepare($query); + $emailStmt->execute(['email' => $email]); + + if ($emailStmt->fetch()) { + $this->line("FOUND: {$email} in {$dbName}.{$userTable}"); + $found = true; + } + } + + if (!$found) { + $this->line("NOT FOUND: {$email}"); + } + + $this->line('--------------------------------------------------'); + } + + return 0; + } + +} From c167bf91d57a085d1c04abc881d5c5eb5f220147 Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Thu, 8 Jan 2026 15:15:46 +0100 Subject: [PATCH 2/5] fix linting --- app/Console/Commands/User/CheckUserEmailExist.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/User/CheckUserEmailExist.php b/app/Console/Commands/User/CheckUserEmailExist.php index ffbfc5cc..7d61c877 100644 --- a/app/Console/Commands/User/CheckUserEmailExist.php +++ b/app/Console/Commands/User/CheckUserEmailExist.php @@ -6,9 +6,9 @@ use Illuminate\Console\Command; use PDO; -class CheckUserEmailExist extends Command{ - +class CheckUserEmailExist extends Command { protected $signature = 'wbs-user:check-email {emails*}'; + protected $description = 'Check if emails exist in apidb.users or any MediaWiki user table'; public function handle(): int { @@ -25,15 +25,15 @@ public function handle(): int { foreach ($emails as $email) { $found = false; - //Check apidb.users + // Check apidb.users if (User::whereEmail($email)->exists()) { $this->line("FOUND: {$email} in apidb.users"); $found = true; } - //Check MediaWiki databases + // Check MediaWiki databases foreach ($mwDatabases as $dbName) { - //fetch user table name + // fetch user table name $tableStmt = $pdo->prepare(" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES @@ -72,5 +72,4 @@ public function handle(): int { return 0; } - } From 5bdd21b916d77c8e385e9dac4c15378089e7cb2f Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Thu, 8 Jan 2026 16:17:08 +0100 Subject: [PATCH 3/5] Added tests --- .../Commands/User/CheckUserEmailExistTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/Commands/User/CheckUserEmailExistTest.php diff --git a/tests/Commands/User/CheckUserEmailExistTest.php b/tests/Commands/User/CheckUserEmailExistTest.php new file mode 100644 index 00000000..818e9554 --- /dev/null +++ b/tests/Commands/User/CheckUserEmailExistTest.php @@ -0,0 +1,25 @@ +create([ + 'email' => 'user@example.com', + ]); + + // Act & Assert + $this->artisan('wbs-user:check-email', ['emails' => ['user@example.com']]) + ->expectsOutput('FOUND: user@example.com in apidb.users') + ->assertExitCode(0); + } + + public function testItReturnsNotFoundIfEmailDoesNotExist() { + $this->artisan('wbs-user:check-email', ['emails' => ['nonexistent@example.com']]) + ->expectsOutput('NOT FOUND: nonexistent@example.com') + ->assertExitCode(0); + } +} From 585e740f2b071a3e359231c9b91feb47126d536c Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Thu, 8 Jan 2026 22:00:01 +0100 Subject: [PATCH 4/5] Add more test --- tests/Commands/User/CheckUserEmailExistTest.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/Commands/User/CheckUserEmailExistTest.php b/tests/Commands/User/CheckUserEmailExistTest.php index 818e9554..5d7af0e4 100644 --- a/tests/Commands/User/CheckUserEmailExistTest.php +++ b/tests/Commands/User/CheckUserEmailExistTest.php @@ -6,7 +6,7 @@ use Tests\TestCase; class CheckUserEmailExistTest extends TestCase { - public function testItFindsEmailInApidbUsersTable() { + public function testItFindsEmailInApiUsersTable() { User::factory()->create([ 'email' => 'user@example.com', ]); @@ -22,4 +22,15 @@ public function testItReturnsNotFoundIfEmailDoesNotExist() { ->expectsOutput('NOT FOUND: nonexistent@example.com') ->assertExitCode(0); } + + public function testItChecksMultipleEmails() { + User::factory()->create(['email' => 'user1@example.com']); + + $emails = ['user1@example.com', 'other@example.com']; + + $this->artisan('wbs-user:check-email', ['emails' => $emails]) + ->expectsOutput('FOUND: user1@example.com in apidb.users') + ->expectsOutput('NOT FOUND: other@example.com') + ->assertExitCode(0); + } } From 5fafbcee36df22422d8dc85eb32c1549cff3357a Mon Sep 17 00:00:00 2001 From: Perside Rosalie Date: Fri, 9 Jan 2026 13:13:36 +0100 Subject: [PATCH 5/5] Refactor checking user email in a service to make testing easier --- .../Commands/User/CheckUserEmailExist.php | 49 +++------------ app/Services/WikiUserEmailChecker.php | 62 +++++++++++++++++++ .../Commands/User/CheckUserEmailExistTest.php | 18 ++++++ 3 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 app/Services/WikiUserEmailChecker.php diff --git a/app/Console/Commands/User/CheckUserEmailExist.php b/app/Console/Commands/User/CheckUserEmailExist.php index 7d61c877..5b33f180 100644 --- a/app/Console/Commands/User/CheckUserEmailExist.php +++ b/app/Console/Commands/User/CheckUserEmailExist.php @@ -2,72 +2,37 @@ namespace App\Console\Commands\User; +use App\Services\WikiUserEmailChecker; use App\User; use Illuminate\Console\Command; -use PDO; class CheckUserEmailExist extends Command { protected $signature = 'wbs-user:check-email {emails*}'; protected $description = 'Check if emails exist in apidb.users or any MediaWiki user table'; - public function handle(): int { + public function handle(WikiUserEmailChecker $emailChecker): int { $emails = $this->argument('emails'); - - $manager = app()->db; - $manager->purge('mw'); - $mwConn = $manager->connection('mw'); - $pdo = $mwConn->getPdo(); - - $dbStmt = $pdo->query("SHOW DATABASES LIKE 'mwdb_%'"); - $mwDatabases = $dbStmt->fetchAll(PDO::FETCH_COLUMN); - foreach ($emails as $email) { $found = false; - // Check apidb.users if (User::whereEmail($email)->exists()) { $this->line("FOUND: {$email} in apidb.users"); $found = true; } - // Check MediaWiki databases - foreach ($mwDatabases as $dbName) { - // fetch user table name - $tableStmt = $pdo->prepare(" - SELECT TABLE_NAME - FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_SCHEMA = :db - AND TABLE_NAME LIKE '%\_user' - LIMIT 1 - "); - $tableStmt->execute(['db' => $dbName]); - $userTable = $tableStmt->fetchColumn(); - if (!$userTable) { - continue; - } + $mwResults = $emailChecker->findEmail($email); - $query = " - SELECT user_id - FROM {$dbName}.{$userTable} - WHERE user_email = :email - LIMIT 1 - "; - - $emailStmt = $pdo->prepare($query); - $emailStmt->execute(['email' => $email]); - - if ($emailStmt->fetch()) { - $this->line("FOUND: {$email} in {$dbName}.{$userTable}"); - $found = true; - } + foreach ($mwResults as $location) { + $this->line("FOUND: {$email} in {$location}"); + $found = true; } if (!$found) { $this->line("NOT FOUND: {$email}"); } - $this->line('--------------------------------------------------'); + $this->line('-------------------------------------------------'); } return 0; diff --git a/app/Services/WikiUserEmailChecker.php b/app/Services/WikiUserEmailChecker.php new file mode 100644 index 00000000..fff4c9ed --- /dev/null +++ b/app/Services/WikiUserEmailChecker.php @@ -0,0 +1,62 @@ +db->purge('mw'); + $pdo = $this->db->connection('mw')->getPdo(); + + $mwDatabases = $pdo + ->query("SHOW DATABASES LIKE 'mwdb_%'") + ->fetchAll(PDO::FETCH_COLUMN); + + $foundIn = []; + + foreach ($mwDatabases as $dbName) { + $userTable = $this->findUserTable($pdo, $dbName); + + if (!$userTable) { + continue; + } + + if ($this->emailExists($pdo, $dbName, $userTable, $email)) { + $foundIn[] = "{$dbName}.{$userTable}"; + } + } + + return $foundIn; + } + + private function findUserTable(PDO $pdo, string $dbName): ?string { + $stmt = $pdo->prepare(" + SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA = :db + AND TABLE_NAME LIKE '%\_user' + LIMIT 1 + "); + + $stmt->execute(['db' => $dbName]); + + return $stmt->fetchColumn() ?: null; + } + + private function emailExists(PDO $pdo, string $dbName, string $table, string $email): bool { + $stmt = $pdo->prepare(" + SELECT 1 + FROM {$dbName}.{$table} + WHERE user_email = :email + LIMIT 1 + "); + + $stmt->execute(['email' => $email]); + + return (bool) $stmt->fetch(); + } +} diff --git a/tests/Commands/User/CheckUserEmailExistTest.php b/tests/Commands/User/CheckUserEmailExistTest.php index 5d7af0e4..57d74867 100644 --- a/tests/Commands/User/CheckUserEmailExistTest.php +++ b/tests/Commands/User/CheckUserEmailExistTest.php @@ -2,7 +2,9 @@ namespace Tests\Commands; +use App\Services\WikiUserEmailChecker; use App\User; +use Mockery; use Tests\TestCase; class CheckUserEmailExistTest extends TestCase { @@ -33,4 +35,20 @@ public function testItChecksMultipleEmails() { ->expectsOutput('NOT FOUND: other@example.com') ->assertExitCode(0); } + + public function testEmailFoundInWikiDb() { + $checker = Mockery::mock(WikiUserEmailChecker::class); + + $checker->shouldReceive('findEmail') + ->with('test@example.com') + ->andReturn(['mwdb_test.mwdb_test_user']); + + $this->app->instance(WikiUserEmailChecker::class, $checker); + + $this->artisan('wbs-user:check-email', [ + 'emails' => ['test@example.com'], + ]) + ->expectsOutput('FOUND: test@example.com in mwdb_test.mwdb_test_user') + ->assertExitCode(0); + } }