feat: implement email case-insensitive queries (fix #318)

This commit is contained in:
xboard
2026-03-28 07:07:57 +08:00
parent a6c37bb112
commit 7fbd1bb92d
9 changed files with 64 additions and 11 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ class ResetPassword extends Command
public function handle() public function handle()
{ {
$password = $this->argument('password') ; $password = $this->argument('password') ;
$user = User::where('email', $this->argument('email'))->first(); $user = User::byEmail($this->argument('email'))->first();
if (!$user) abort(500, '邮箱不存在'); if (!$user) abort(500, '邮箱不存在');
$password = $password ?? Helper::guid(false); $password = $password ?? Helper::guid(false);
$user->password = password_hash($password, PASSWORD_DEFAULT); $user->password = password_hash($password, PASSWORD_DEFAULT);
@@ -29,7 +29,7 @@ class CommController extends Controller
// 检查白名单后缀限制 // 检查白名单后缀限制
if ((int) admin_setting('email_whitelist_enable', 0)) { if ((int) admin_setting('email_whitelist_enable', 0)) {
$isRegisteredEmail = User::where('email', $email)->exists(); $isRegisteredEmail = User::byEmail($email)->exists();
if (!$isRegisteredEmail) { if (!$isRegisteredEmail) {
$allowedSuffixes = Helper::getEmailSuffix(); $allowedSuffixes = Helper::getEmailSuffix();
$emailSuffix = substr(strrchr($email, '@'), 1); $emailSuffix = substr(strrchr($email, '@'), 1);
@@ -199,7 +199,7 @@ class OrderController extends Controller
public function assign(OrderAssign $request) public function assign(OrderAssign $request)
{ {
$plan = Plan::find($request->input('plan_id')); $plan = Plan::find($request->input('plan_id'));
$user = User::where('email', $request->input('email'))->first(); $user = User::byEmail($request->input('email'))->first();
if (!$user) { if (!$user) {
return $this->fail([400202, '该用户不存在']); return $this->fail([400202, '该用户不存在']);
@@ -220,7 +220,7 @@ class UserController extends Controller
return $this->fail([400202, '用户不存在']); return $this->fail([400202, '用户不存在']);
} }
if (isset($params['email'])) { if (isset($params['email'])) {
if (User::where('email', $params['email'])->first() && $user->email !== $params['email']) { if (User::byEmail($params['email'])->first() && $user->email !== $params['email']) {
return $this->fail([400201, '邮箱已被使用']); return $this->fail([400201, '邮箱已被使用']);
} }
} }
@@ -240,7 +240,7 @@ class UserController extends Controller
$params['group_id'] = $plan->group_id; $params['group_id'] = $plan->group_id;
} }
// 处理邀请用户 // 处理邀请用户
if ($request->input('invite_user_email') && $inviteUser = User::where('email', $request->input('invite_user_email'))->first()) { if ($request->input('invite_user_email') && $inviteUser = User::byEmail($request->input('invite_user_email'))->first()) {
$params['invite_user_id'] = $inviteUser->id; $params['invite_user_id'] = $inviteUser->id;
} else { } else {
$params['invite_user_id'] = null; $params['invite_user_id'] = null;
@@ -365,7 +365,7 @@ class UserController extends Controller
if ($request->input('email_prefix')) { if ($request->input('email_prefix')) {
$email = $request->input('email_prefix') . '@' . $request->input('email_suffix'); $email = $request->input('email_prefix') . '@' . $request->input('email_suffix');
if (User::where('email', $email)->exists()) { if (User::byEmail($email)->exists()) {
return $this->fail([400201, '邮箱已存在于系统中']); return $this->fail([400201, '邮箱已存在于系统中']);
} }
+16
View File
@@ -3,6 +3,8 @@
namespace App\Models; namespace App\Models;
use App\Utils\Helper; use App\Utils\Helper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Sanctum\HasApiTokens;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -81,6 +83,20 @@ class User extends Authenticatable
public const COMMISSION_TYPE_SYSTEM = 0; public const COMMISSION_TYPE_SYSTEM = 0;
public const COMMISSION_TYPE_PERIOD = 1; public const COMMISSION_TYPE_PERIOD = 1;
public const COMMISSION_TYPE_ONETIME = 2; public const COMMISSION_TYPE_ONETIME = 2;
protected function email(): Attribute
{
return Attribute::make(
set: fn (string $value) => strtolower(trim($value)),
);
}
/**
* 按邮箱查询(大小写不敏感,兼容所有数据库)
*/
public function scopeByEmail(Builder $query, string $email): Builder
{
return $query->where('email', strtolower(trim($email)));
}
// 获取邀请人信息 // 获取邀请人信息
public function invite_user(): BelongsTo public function invite_user(): BelongsTo
+2 -2
View File
@@ -36,7 +36,7 @@ class LoginService
} }
// 查找用户 // 查找用户
$user = User::where('email', $email)->first(); $user = User::byEmail($email)->first();
if (!$user) { if (!$user) {
return [false, [400, __('Incorrect email or password')]]; return [false, [400, __('Incorrect email or password')]];
} }
@@ -99,7 +99,7 @@ class LoginService
} }
// 查找用户 // 查找用户
$user = User::where('email', $email)->first(); $user = User::byEmail($email)->first();
if (!$user) { if (!$user) {
return [false, [400, __('This email is not registered in the system')]]; return [false, [400, __('This email is not registered in the system')]];
} }
+1 -1
View File
@@ -27,7 +27,7 @@ class MailLinkService
return [false, [429, __('Sending frequently, please try again later')]]; return [false, [429, __('Sending frequently, please try again later')]];
} }
$user = User::where('email', $email)->first(); $user = User::byEmail($email)->first();
if (!$user) { if (!$user) {
return [true, true]; // 成功但用户不存在,保护用户隐私 return [true, true]; // 成功但用户不存在,保护用户隐私
} }
+1 -2
View File
@@ -91,8 +91,7 @@ class RegisterService
} }
// 检查邮箱是否存在 // 检查邮箱是否存在
$email = $request->input('email'); $exist = User::byEmail($request->input('email'))->first();
$exist = User::where('email', $email)->first();
if ($exist) { if ($exist) {
return [false, [400201, __('Email already exists')]]; return [false, [400201, __('Email already exists')]];
} }
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
// 统计需要转换的记录数
$count = DB::table('v2_user')
->whereNotNull('email')
->whereRaw('email != LOWER(email)')
->count();
if ($count > 0) {
Log::info("Converting {$count} email(s) to lowercase");
DB::table('v2_user')
->whereNotNull('email')
->whereRaw('email != LOWER(email)')
->update(['email' => DB::raw('LOWER(email)')]);
Log::info("Email lowercase conversion completed");
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// 无法恢复原始大小写
}
};