Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/Console/Commands/User/CheckUserEmailExist.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function handle(WikiUserEmailChecker $emailChecker): int {
foreach ($emails as $email) {
$found = false;

if (User::whereEmail($email)->exists()) {
if (User::whereEmailInsensitive($email)->exists()) {
$this->line("FOUND: {$email} in apidb.users");
$found = true;
}
Expand Down
2 changes: 1 addition & 1 deletion app/Services/WikiUserEmailChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private function emailExists(PDO $pdo, string $dbName, string $table, string $em
$stmt = $pdo->prepare("
SELECT 1
FROM {$dbName}.{$table}
WHERE user_email = :email
WHERE LOWER(CONVERT(user_email USING utf8mb4)) = LOWER(:email)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks interesting, and it's not immediately obvious to me why it is needed. Can we add a comment above this line to explain it?

Copy link
Contributor

@deer-wmde deer-wmde Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the table schema, the datatype of the user_email field is tinyblob, so I guess it makes sense (or is maybe even necessary) for the comparison: https://github.com/wbstack/api/blob/main/database/mw/new/mw1.43-wbs2.sql#L1005

edit:

gave it a quick test:

MariaDB root@localhost:mwdb_8127892d75> SELECT user_email FROM mwt_022411e763_user WHERE LOWER(CONVERT(user_email USING utf8mb4)) = LOWER('DENA@DENA.DENA') \G
***************************[ 1. row ]***************************
user_email | Dena@DENA.dena

1 row in set
Time: 0.002s

MariaDB root@localhost:mwdb_8127892d75> SELECT user_email FROM mwt_022411e763_user WHERE LOWER(user_email) = LOWER('DENA@DENA.DENA') \G
0 rows in set
Time: 0.002s

LIMIT 1
");

Expand Down
4 changes: 4 additions & 0 deletions app/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,8 @@ public function sendEmailVerificationNotification() {
public function getEmailForVerification() {
return $this->email;
}

public function scopeWhereEmailInsensitive($query, string $email) {
return $query->whereRaw('LOWER(email) = ?', [strtolower($email)]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required? Looking at the quick test I did the case-insensitive searching worked for the Platform API users table. I believe this is because the email column uses the utf8mb4_unicode_ci collation. The ci stands for case-insensitive.

We should still keep the tests that prove that case-insensitive search works, though.

P.S. an FYI for the future, strtolower() only converts ASCII alphabetic characters. mb_strtolower() is needed to convert non-ASCII character as well.

}
}
13 changes: 13 additions & 0 deletions tests/Commands/User/CheckUserEmailExistTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
use Tests\TestCase;

class CheckUserEmailExistTest extends TestCase {
protected function tearDown(): void {
User::query()->delete();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
User::query()->delete();
// delete all users
User::query()->delete();

}

public function testItFindsEmailInApiUsersTable() {
User::factory()->create([
'email' => 'user@example.com',
Expand Down Expand Up @@ -51,4 +55,13 @@ public function testEmailFoundInWikiDb() {
->expectsOutput('FOUND: test@example.com in mwdb_test.mwdb_test_user')
->assertExitCode(0);
}

public function testCaseInsensitive() {
User::factory()->create([
'email' => 'Test@Example.com',
]);
$exists = User::whereEmailInsensitive('tEsT@eXaMpLe.CoM')->exists();

$this->assertTrue($exists);
}
}
9 changes: 9 additions & 0 deletions tests/Services/WikiUserEmailCheckerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class WikiUserEmailCheckerTest extends TestCase {
['prefix' => 'db_1', 'name' => 'mwdb_1', 'emails' => ['user1@email.localhost', 'user2@email.localhost']],
['prefix' => 'db_2', 'name' => 'mwdb_2', 'emails' => ['user1@email.localhost']],
['prefix' => 'db_3', 'name' => 'mwdb_3', 'emails' => []],
['prefix' => 'db_4', 'name' => 'mwdb_4', 'emails' => ['UsEr4@EmAiL.lOcAlHoSt']],
];

protected function setUp(): void {
Expand Down Expand Up @@ -62,4 +63,12 @@ public function testEmailFoundInMultipleDatabases(): void {
$checker->findEmail('user1@email.localhost')
);
}

public function testWikiUserEmailCheckerIsCaseInsensitive(): void {
$checker = new WikiUserEmailChecker($this->db);
$this->assertEquals(
['mwdb_4.db_4_user'],
$checker->findEmail('uSer4@eMAil.localhost')
);
}
}
Loading