Mark-Lasfar commited on
Commit
32b6b18
·
1 Parent(s): a093617

Update backend and server frontend for OAuth JSON response, client-side navigation, and add .gitignore

Browse files
Files changed (4) hide show
  1. api/auth.py +4 -4
  2. static/js/chat.js +30 -2
  3. templates/chat.html +2 -1
  4. templates/login.html +154 -128
api/auth.py CHANGED
@@ -257,8 +257,8 @@ async def custom_oauth_callback(
257
  "access_token": token
258
  }, status_code=200)
259
  else:
260
- # للويب: إرجاع redirect إلى /chat
261
- return RedirectResponse(url="/chat", status_code=303)
262
 
263
  except Exception as e:
264
  logger.error(f"Error in Google OAuth callback: {str(e)}")
@@ -346,8 +346,8 @@ async def custom_github_oauth_callback(
346
  "access_token": token
347
  }, status_code=200)
348
  else:
349
- # للويب: إرجاع redirect إلى /chat
350
- return RedirectResponse(url="/chat", status_code=303)
351
 
352
  except Exception as e:
353
  logger.error(f"Error in GitHub OAuth callback: {str(e)}")
 
257
  "access_token": token
258
  }, status_code=200)
259
  else:
260
+ # للويب: إرجاع redirect إلى /chat مع الـ token كـ query parameter
261
+ return RedirectResponse(url=f"/chat?access_token={token}", status_code=303)
262
 
263
  except Exception as e:
264
  logger.error(f"Error in Google OAuth callback: {str(e)}")
 
346
  "access_token": token
347
  }, status_code=200)
348
  else:
349
+ # للويب: إرجاع redirect إلى /chat مع الـ token كـ query parameter
350
+ return RedirectResponse(url=f"/chat?access_token={token}", status_code=303)
351
 
352
  except Exception as e:
353
  logger.error(f"Error in GitHub OAuth callback: {str(e)}")
static/js/chat.js CHANGED
@@ -101,11 +101,33 @@ document.addEventListener('DOMContentLoaded', async () => {
101
 
102
  // Check authentication token
103
  async function checkAuth() {
104
- const token = localStorage.getItem('token');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  if (!token) {
106
- console.log('No auth token found in localStorage');
107
  return { authenticated: false, user: null };
108
  }
 
109
  try {
110
  const response = await fetch('/api/verify-token', {
111
  method: 'GET',
@@ -121,11 +143,17 @@ async function checkAuth() {
121
  } else {
122
  console.log('Token verification failed:', data.detail || response.status);
123
  localStorage.removeItem('token');
 
 
 
124
  return { authenticated: false, user: null };
125
  }
126
  } catch (error) {
127
  console.error('Error verifying token:', error);
128
  localStorage.removeItem('token');
 
 
 
129
  return { authenticated: false, user: null };
130
  }
131
  }
 
101
 
102
  // Check authentication token
103
  async function checkAuth() {
104
+ // تحقق من وجود token في query parameters
105
+ const urlParams = new URLSearchParams(window.location.search);
106
+ const accessTokenFromUrl = urlParams.get('access_token');
107
+ if (accessTokenFromUrl) {
108
+ console.log('Access token found in URL, saving to localStorage');
109
+ localStorage.setItem('token', accessTokenFromUrl);
110
+ // إزالة الـ access_token من الـ URL عشان الأمان
111
+ window.history.replaceState({}, document.title, '/chat');
112
+ }
113
+
114
+ // تحقق من وجود token في localStorage
115
+ let token = localStorage.getItem('token');
116
+
117
+ // لو مفيش token في localStorage، حاول استخرج الـ token من الـ cookie (اختياري)
118
+ if (!token && typeof Cookies !== 'undefined') {
119
+ token = Cookies.get('fastapiusersauth');
120
+ if (token) {
121
+ console.log('Access token found in cookie, saving to localStorage');
122
+ localStorage.setItem('token', token);
123
+ }
124
+ }
125
+
126
  if (!token) {
127
+ console.log('No auth token found in localStorage or cookie');
128
  return { authenticated: false, user: null };
129
  }
130
+
131
  try {
132
  const response = await fetch('/api/verify-token', {
133
  method: 'GET',
 
143
  } else {
144
  console.log('Token verification failed:', data.detail || response.status);
145
  localStorage.removeItem('token');
146
+ if (typeof Cookies !== 'undefined') {
147
+ Cookies.remove('fastapiusersauth');
148
+ }
149
  return { authenticated: false, user: null };
150
  }
151
  } catch (error) {
152
  console.error('Error verifying token:', error);
153
  localStorage.removeItem('token');
154
+ if (typeof Cookies !== 'undefined') {
155
+ Cookies.remove('fastapiusersauth');
156
+ }
157
  return { authenticated: false, user: null };
158
  }
159
  }
templates/chat.html CHANGED
@@ -420,6 +420,7 @@
420
  <!-- Scripts -->
421
  <script src="/static/js/chat.js?v=1.2"></script>
422
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
 
423
 
424
  <script>
425
  // تهيئة مكتبة AOS
@@ -475,4 +476,4 @@
475
 
476
  </body>
477
 
478
- </html>
 
420
  <!-- Scripts -->
421
  <script src="/static/js/chat.js?v=1.2"></script>
422
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
423
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/3.0.1/js.cookie.min.js"></script>
424
 
425
  <script>
426
  // تهيئة مكتبة AOS
 
476
 
477
  </body>
478
 
479
+ </html>
templates/login.html CHANGED
@@ -429,145 +429,146 @@
429
 
430
  // Check authentication status
431
  async function checkAuthStatus() {
432
- const token = localStorage.getItem('token');
433
- if (!token) {
434
- console.log('No token found in localStorage');
435
- return false;
436
- }
437
- try {
438
- const response = await fetch('/api/verify-token', {
439
- method: 'GET',
440
- headers: {
441
- 'Authorization': `Bearer ${token}`,
442
- 'Accept': 'application/json'
443
- }
444
- });
445
- const data = await response.json();
446
- if (response.ok && data.status === 'valid') {
447
- console.log('Token is valid, user:', data.user);
448
- return true;
449
- } else {
450
- console.log('Token verification failed:', data.detail || 'Invalid token');
451
- localStorage.removeItem('token');
452
- return false;
453
  }
454
- } catch (error) {
455
- console.error('Error verifying token:', error);
 
 
 
 
 
456
  localStorage.removeItem('token');
457
  return false;
458
  }
 
 
 
 
459
  }
 
460
 
461
  // Handle email/password login
462
- const loginForm = document.getElementById('loginForm');
463
- const loginBtn = document.getElementById('loginBtn');
464
- const spinner = document.getElementById('spinner');
465
- const errorMsg = document.getElementById('errorMsg');
466
- const googleLoginBtn = document.getElementById('googleLoginBtn');
467
- const githubLoginBtn = document.getElementById('githubLoginBtn');
 
468
 
469
  if (loginForm) {
470
- loginForm.addEventListener('submit', async (e) => {
471
- e.preventDefault();
472
- console.log('Login form submitted');
473
- if (!navigator.onLine) {
474
- errorMsg.textContent = 'You are offline. Please connect to the internet and try again.';
475
- errorMsg.classList.remove('hidden');
476
- return;
477
- }
478
- spinner.classList.remove('hidden');
479
- errorMsg.classList.add('hidden');
480
- const formData = new FormData(loginForm);
481
- try {
482
- const response = await fetch('/auth/jwt/login', {
483
- method: 'POST',
484
- body: formData
485
- });
486
- spinner.classList.add('hidden');
487
- if (response.ok) {
488
- const data = await response.json();
489
- localStorage.setItem('token', data.access_token);
490
- console.log('Login successful, redirecting to /chat');
491
- window.location.href = '/chat';
492
- } else {
493
- const error = await response.json();
494
- errorMsg.textContent = error.detail || 'Login failed. Please try again.';
495
- errorMsg.classList.remove('hidden');
496
- console.error('Login failed:', error);
497
- }
498
- } catch (error) {
499
- spinner.classList.add('hidden');
500
- errorMsg.textContent = 'An error occurred. Please try again.';
501
  errorMsg.classList.remove('hidden');
502
- console.error('Error during login:', error);
503
  }
504
- });
505
- }
 
 
 
 
 
 
506
 
507
- // Handle Google OAuth login
508
- if (googleLoginBtn) {
509
- googleLoginBtn.addEventListener('click', async (e) => {
510
- e.preventDefault();
511
- console.log('Google login button clicked');
512
- spinner.classList.remove('hidden');
513
- errorMsg.classList.add('hidden');
514
- try {
515
- const response = await fetch('/auth/google/authorize', {
516
- method: 'GET',
517
- headers: { 'Accept': 'application/json' }
518
- });
519
- if (!response.ok) {
520
- throw new Error(`HTTP error! Status: ${response.status}`);
521
- }
522
- const data = await response.json();
523
- if (data.authorization_url) {
524
- console.log('Redirecting to Google:', data.authorization_url);
525
- window.location.href = data.authorization_url;
526
- } else {
527
- throw new Error('No authorization URL received');
528
- }
529
- } catch (error) {
530
- spinner.classList.add('hidden');
531
- errorMsg.textContent = 'Failed to initiate Google login. Please try again.';
532
- errorMsg.classList.remove('hidden');
533
- console.error('Error initiating Google login:', error);
534
  }
535
- });
536
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
537
 
538
- // Handle GitHub OAuth login
539
- if (githubLoginBtn) {
540
- githubLoginBtn.addEventListener('click', async (e) => {
541
- e.preventDefault();
542
- console.log('GitHub login button clicked');
543
- spinner.classList.remove('hidden');
544
- errorMsg.classList.add('hidden');
545
- try {
546
- const response = await fetch('/auth/github/authorize', {
547
- method: 'GET',
548
- headers: { 'Accept': 'application/json' }
549
- });
550
- if (!response.ok) {
551
- throw new Error(`HTTP error! Status: ${response.status}`);
552
- }
553
- const data = await response.json();
554
- if (data.authorization_url) {
555
- console.log('Redirecting to GitHub:', data.authorization_url);
556
- window.location.href = data.authorization_url;
557
- } else {
558
- throw new Error('No authorization URL received');
559
- }
560
- } catch (error) {
561
- spinner.classList.add('hidden');
562
- errorMsg.textContent = 'Failed to initiate GitHub login. Please try again.';
563
- errorMsg.classList.remove('hidden');
564
- console.error('Error initiating GitHub login:', error);
565
  }
566
- });
567
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
568
 
569
- // Check for OAuth callback on load
570
- window.addEventListener('load', async () => {
571
  console.log('Page loaded, checking for auth status and OAuth callback');
572
  if (!navigator.onLine) {
573
  errorMsg.textContent = 'You are offline. Please connect to the internet and try again.';
@@ -584,14 +585,39 @@
584
  const urlParams = new URLSearchParams(window.location.search);
585
  const code = urlParams.get('code');
586
  const error = urlParams.get('error');
 
 
587
  if (error) {
588
  errorMsg.textContent = decodeURIComponent(error);
589
  errorMsg.classList.remove('hidden');
590
  console.error('OAuth error from URL:', error);
591
- } else if (code) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  console.log('OAuth code detected in URL, processing callback');
593
  const provider = window.location.pathname.includes('google') ? 'google' : 'github';
594
  try {
 
595
  const response = await fetch(window.location.href, {
596
  method: 'GET',
597
  headers: { 'Accept': 'application/json' }
@@ -625,10 +651,10 @@
625
  }
626
  });
627
  // Handle card details toggle
628
- function showCardDetails(cardId) {
629
- console.log('Showing card details:', cardId);
630
- document.getElementById(`${cardId}-details`).classList.remove('hidden');
631
- }
632
 
633
  function closeCardDetails(cardId) {
634
  console.log('Closing card details:', cardId);
 
429
 
430
  // Check authentication status
431
  async function checkAuthStatus() {
432
+ const token = localStorage.getItem('token');
433
+ if (!token) {
434
+ console.log('No token found in localStorage');
435
+ return false;
436
+ }
437
+ try {
438
+ const response = await fetch('/api/verify-token', {
439
+ method: 'GET',
440
+ headers: {
441
+ 'Authorization': `Bearer ${token}`,
442
+ 'Accept': 'application/json'
 
 
 
 
 
 
 
 
 
 
443
  }
444
+ });
445
+ const data = await response.json();
446
+ if (response.ok && data.status === 'valid') {
447
+ console.log('Token is valid, user:', data.user);
448
+ return true;
449
+ } else {
450
+ console.log('Token verification failed:', data.detail || 'Invalid token');
451
  localStorage.removeItem('token');
452
  return false;
453
  }
454
+ } catch (error) {
455
+ console.error('Error verifying token:', error);
456
+ localStorage.removeItem('token');
457
+ return false;
458
  }
459
+ }
460
 
461
  // Handle email/password login
462
+ const loginForm = document.getElementById('loginForm');
463
+ const loginBtn = document.getElementById('loginBtn');
464
+ const spinner = document.getElementById('spinner');
465
+ const errorMsg = document.getElementById('errorMsg');
466
+ const googleLoginBtn = document.getElementById('googleLoginBtn');
467
+ const githubLoginBtn = document.getElementById('githubLoginBtn');
468
+
469
 
470
  if (loginForm) {
471
+ loginForm.addEventListener('submit', async (e) => {
472
+ e.preventDefault();
473
+ console.log('Login form submitted');
474
+ if (!navigator.onLine) {
475
+ errorMsg.textContent = 'You are offline. Please connect to the internet and try again.';
476
+ errorMsg.classList.remove('hidden');
477
+ return;
478
+ }
479
+ spinner.classList.remove('hidden');
480
+ errorMsg.classList.add('hidden');
481
+ const formData = new FormData(loginForm);
482
+ try {
483
+ const response = await fetch('/auth/jwt/login', {
484
+ method: 'POST',
485
+ body: formData
486
+ });
487
+ spinner.classList.add('hidden');
488
+ if (response.ok) {
489
+ const data = await response.json();
490
+ localStorage.setItem('token', data.access_token);
491
+ console.log('Login successful, redirecting to /chat');
492
+ window.location.href = '/chat';
493
+ } else {
494
+ const error = await response.json();
495
+ errorMsg.textContent = error.detail || 'Login failed. Please try again.';
 
 
 
 
 
 
496
  errorMsg.classList.remove('hidden');
497
+ console.error('Login failed:', error);
498
  }
499
+ } catch (error) {
500
+ spinner.classList.add('hidden');
501
+ errorMsg.textContent = 'An error occurred. Please try again.';
502
+ errorMsg.classList.remove('hidden');
503
+ console.error('Error during login:', error);
504
+ }
505
+ });
506
+ }
507
 
508
+ // Handle Google OAuth login
509
+ if (googleLoginBtn) {
510
+ googleLoginBtn.addEventListener('click', async (e) => {
511
+ e.preventDefault();
512
+ console.log('Google login button clicked');
513
+ spinner.classList.remove('hidden');
514
+ errorMsg.classList.add('hidden');
515
+ try {
516
+ const response = await fetch('/auth/google/authorize', {
517
+ method: 'GET',
518
+ headers: { 'Accept': 'application/json' }
519
+ });
520
+ if (!response.ok) {
521
+ throw new Error(`HTTP error! Status: ${response.status}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
522
  }
523
+ const data = await response.json();
524
+ if (data.authorization_url) {
525
+ console.log('Redirecting to Google:', data.authorization_url);
526
+ window.location.href = data.authorization_url;
527
+ } else {
528
+ throw new Error('No authorization URL received');
529
+ }
530
+ } catch (error) {
531
+ spinner.classList.add('hidden');
532
+ errorMsg.textContent = 'Failed to initiate Google login. Please try again.';
533
+ errorMsg.classList.remove('hidden');
534
+ console.error('Error initiating Google login:', error);
535
+ }
536
+ });
537
+ }
538
 
539
+ // Handle GitHub OAuth login
540
+ if (githubLoginBtn) {
541
+ githubLoginBtn.addEventListener('click', async (e) => {
542
+ e.preventDefault();
543
+ console.log('GitHub login button clicked');
544
+ spinner.classList.remove('hidden');
545
+ errorMsg.classList.add('hidden');
546
+ try {
547
+ const response = await fetch('/auth/github/authorize', {
548
+ method: 'GET',
549
+ headers: { 'Accept': 'application/json' }
550
+ });
551
+ if (!response.ok) {
552
+ throw new Error(`HTTP error! Status: ${response.status}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  }
554
+ const data = await response.json();
555
+ if (data.authorization_url) {
556
+ console.log('Redirecting to GitHub:', data.authorization_url);
557
+ window.location.href = data.authorization_url;
558
+ } else {
559
+ throw new Error('No authorization URL received');
560
+ }
561
+ } catch (error) {
562
+ spinner.classList.add('hidden');
563
+ errorMsg.textContent = 'Failed to initiate GitHub login. Please try again.';
564
+ errorMsg.classList.remove('hidden');
565
+ console.error('Error initiating GitHub login:', error);
566
+ }
567
+ });
568
+ }
569
 
570
+ // Check for OAuth callback on load
571
+ window.addEventListener('load', async () => {
572
  console.log('Page loaded, checking for auth status and OAuth callback');
573
  if (!navigator.onLine) {
574
  errorMsg.textContent = 'You are offline. Please connect to the internet and try again.';
 
585
  const urlParams = new URLSearchParams(window.location.search);
586
  const code = urlParams.get('code');
587
  const error = urlParams.get('error');
588
+ const accessToken = urlParams.get('access_token'); // إضافة فحص access_token في الـ URL
589
+
590
  if (error) {
591
  errorMsg.textContent = decodeURIComponent(error);
592
  errorMsg.classList.remove('hidden');
593
  console.error('OAuth error from URL:', error);
594
+ return;
595
+ }
596
+
597
+ // إذا وجد access_token في الـ URL (من redirect الباك إند)
598
+ if (accessToken) {
599
+ console.log('Access token found in URL, saving to localStorage');
600
+ localStorage.setItem('token', accessToken);
601
+ // إزالة access_token من الـ URL عشان الأمان
602
+ window.history.replaceState({}, document.title, window.location.pathname);
603
+ const isAuthenticated = await checkAuthStatus();
604
+ if (isAuthenticated) {
605
+ console.log('Redirecting to /chat after saving token');
606
+ window.location.href = '/chat';
607
+ } else {
608
+ errorMsg.textContent = 'Authentication failed after receiving token. Please try again.';
609
+ errorMsg.classList.remove('hidden');
610
+ console.error('Authentication failed after receiving token');
611
+ }
612
+ return;
613
+ }
614
+
615
+ // إذا وجد code في الـ URL (حالة الـ OAuth callback)
616
+ if (code) {
617
  console.log('OAuth code detected in URL, processing callback');
618
  const provider = window.location.pathname.includes('google') ? 'google' : 'github';
619
  try {
620
+ // محاولة استدعاء الـ callback endpoint
621
  const response = await fetch(window.location.href, {
622
  method: 'GET',
623
  headers: { 'Accept': 'application/json' }
 
651
  }
652
  });
653
  // Handle card details toggle
654
+ function showCardDetails(cardId) {
655
+ console.log('Showing card details:', cardId);
656
+ document.getElementById(`${cardId}-details`).classList.remove('hidden');
657
+ }
658
 
659
  function closeCardDetails(cardId) {
660
  console.log('Closing card details:', cardId);