feat(auth): connexion avec un compte Google (find-or-create, import likes/abos inclus)

- Backend: GET /api/auth/google/{url,callback} (state login distinct du
  link import), echange code, profil userinfo, find-or-create (OAuth sub,
  puis email), session + cookies comme login interne, connexion stockee
  dans oauth_connections pour l'import direct
- Front: bouton 'Se connecter avec Google' sur /auth/login (visible si
  configure), page /auth/google/callback (initSession + prefs + redirect
  /library/import), cles i18n nav.import deja en place
- Comptes Google-only: password_hash aleatoire (login mot de passe impossible)
This commit is contained in:
2026-09-26 21:02:12 -04:00
parent ecb4295a59
commit 783003822d
9 changed files with 252 additions and 2 deletions
+17
View File
@@ -140,6 +140,23 @@ export function getUserById(id) {
return db.prepare('SELECT * FROM users WHERE id = ?').get(id);
}
export function getUserByEmail(email) {
const clean = String(email || '').trim().toLowerCase();
if (!clean) return null;
return db.prepare('SELECT * FROM users WHERE LOWER(email) = ?').get(clean) || null;
}
/** Retrouve l'utilisateur lié à un compte OAuth externe (ex. Google sub). */
export function getUserByOAuth(provider, externalUserId) {
try {
ensureOAuthTables();
const row = db.prepare(`SELECT u.* FROM oauth_connections oc
JOIN users u ON u.id = oc.user_id
WHERE oc.provider = ? AND oc.external_user_id = ?`).get(provider, String(externalUserId || ''));
return row || null;
} catch { return null; }
}
export function insertUser({ id, username, email, passwordHash }) {
const ts = nowIso();
db.prepare(`INSERT INTO users (id, username, email, password_hash, is_active, created_at, updated_at)