Checkpoint: Le champ de connexion accepte maintenant un identifiant (ex: adminItinova) ou une adresse e-mail. Le backend recherche dans les deux cas. Le label et le placeholder ont été mis à jour.
This commit is contained in:
9
.manus/db/db-query-1774010427110.json
Normal file
9
.manus/db/db-query-1774010427110.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"query": "INSERT INTO local_users (email, passwordHash, name, role, isActive, createdAt, updatedAt)\nVALUES (\n 'adminItinova',\n '$2b$12$BFswq4nzwOXHx1CHW2QIq.qSlfYgJD1iPC07Wx6Bi8V8pKJyK6BBq',\n 'Admin Itinova',\n 'admin',\n 1,\n NOW(),\n NOW()\n);",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.63b125a8f9ca --database VepzDyqR8YkJNcqpZ729Bw --execute INSERT INTO local_users (email, passwordHash, name, role, isActive, createdAt, updatedAt)\nVALUES (\n 'adminItinova',\n '$2b$12$BFswq4nzwOXHx1CHW2QIq.qSlfYgJD1iPC07Wx6Bi8V8pKJyK6BBq',\n 'Admin Itinova',\n 'admin',\n 1,\n NOW(),\n NOW()\n);",
|
||||||
|
"rows": [],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 529
|
||||||
|
}
|
||||||
17
.manus/db/db-query-1774010431849.json
Normal file
17
.manus/db/db-query-1774010431849.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"query": "SELECT id, email, name, role, isActive FROM local_users WHERE email = 'adminItinova';",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.63b125a8f9ca --database VepzDyqR8YkJNcqpZ729Bw --execute SELECT id, email, name, role, isActive FROM local_users WHERE email = 'adminItinova';",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": "60001",
|
||||||
|
"email": "adminItinova",
|
||||||
|
"name": "Admin Itinova",
|
||||||
|
"role": "admin",
|
||||||
|
"isActive": "1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "id\temail\tname\trole\tisActive\n60001\tadminItinova\tAdmin Itinova\tadmin\t1\n",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 53
|
||||||
|
}
|
||||||
@@ -62,11 +62,11 @@ export default function Login() {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<form onSubmit={handleSubmit} className="space-y-4">
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="email">Adresse e-mail</Label>
|
<Label htmlFor="email">Identifiant ou e-mail</Label>
|
||||||
<Input
|
<Input
|
||||||
id="email"
|
id="email"
|
||||||
type="email"
|
type="text"
|
||||||
placeholder="votre@email.fr"
|
placeholder="Identifiant ou e-mail"
|
||||||
value={email}
|
value={email}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import bcrypt from "bcryptjs";
|
import bcrypt from "bcryptjs";
|
||||||
import { getDb } from "./db";
|
import { getDb } from "./db";
|
||||||
import { localUsers } from "../drizzle/schema";
|
import { localUsers } from "../drizzle/schema";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq, or } from "drizzle-orm";
|
||||||
import { SignJWT, jwtVerify } from "jose";
|
import { SignJWT, jwtVerify } from "jose";
|
||||||
import { ENV } from "./_core/env";
|
import { ENV } from "./_core/env";
|
||||||
|
|
||||||
@@ -41,10 +41,17 @@ export async function loginLocalUser(email: string, password: string) {
|
|||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
if (!db) throw new Error("Base de données indisponible");
|
if (!db) throw new Error("Base de données indisponible");
|
||||||
|
|
||||||
|
// Recherche par e-mail (insensible à la casse) OU par identifiant exact
|
||||||
|
const identifier = email.trim();
|
||||||
const users = await db
|
const users = await db
|
||||||
.select()
|
.select()
|
||||||
.from(localUsers)
|
.from(localUsers)
|
||||||
.where(eq(localUsers.email, email.toLowerCase().trim()))
|
.where(
|
||||||
|
or(
|
||||||
|
eq(localUsers.email, identifier.toLowerCase()),
|
||||||
|
eq(localUsers.email, identifier)
|
||||||
|
)
|
||||||
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
const user = users[0];
|
const user = users[0];
|
||||||
|
|||||||
1
todo.md
1
todo.md
@@ -44,3 +44,4 @@
|
|||||||
- [x] Vignettes AAP : coloriser les étiquettes Région (violet) et Date (orange)
|
- [x] Vignettes AAP : coloriser les étiquettes Région (violet) et Date (orange)
|
||||||
- [x] Vignettes Veille : coloriser les étiquettes Niveau (violet), Territoire (teal) et Date (orange)
|
- [x] Vignettes Veille : coloriser les étiquettes Niveau (violet), Territoire (teal) et Date (orange)
|
||||||
- [x] Page Login : supprimer l'encart affichant les identifiants du compte par défaut
|
- [x] Page Login : supprimer l'encart affichant les identifiants du compte par défaut
|
||||||
|
- [x] Login : accepter un identifiant (e-mail ou nom d'utilisateur) au lieu d'un e-mail obligatoire
|
||||||
|
|||||||
Reference in New Issue
Block a user