File size: 5,977 Bytes
e4ab6d0
 
 
 
 
 
 
 
 
 
 
 
 
e664319
 
 
e4ab6d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8794d4
e4ab6d0
 
 
f8794d4
 
 
 
e4ab6d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
import { Router } from '@angular/router';



@Injectable({
  providedIn: 'root'
})

export class AuthService {
  private apiUrl = location.hostname.endsWith('hf.space')
    ? 'https://pykara-py-learn-backend.hf.space'
    : 'http://localhost:5000'; // Your Flask API base URL
  private loggedInSubject = new BehaviorSubject<boolean>(false);  // Shared state
  public isLoggedIn$ = this.loggedInSubject.asObservable();
  private refreshIntervalId: any;
  constructor(private http: HttpClient, private router: Router) { }

  // βœ… Called to check current status
  isLoggedIn(): boolean {
    return this.loggedInSubject.value;
  }

  // βœ… Set login status manually
  setLoggedIn(status: boolean): void {
    this.loggedInSubject.next(status);
  }
  // βœ… Login Method


  login(username: string, password: string): Observable<any> {
  return this.http.post(`${this.apiUrl}/login`, { username, password }, { withCredentials: true });
  }


  startAutoRefresh(): void {
    if (this.refreshIntervalId) return;
    this.refreshIntervalId = setInterval(() => {
      this.refreshAccessToken();
    }, 12 * 60 * 1000);
  }

  clearAutoRefresh(): void {
    clearInterval(this.refreshIntervalId);
    this.refreshIntervalId = null;
  }

  refreshAccessToken(): void {
    this.http.post(`${this.apiUrl}/refresh`, {}, { withCredentials: true }).subscribe(
      (response: any) => {
        console.log("βœ… Access token refreshed:", response.access_token);
        //alert("πŸ”„ Access token has been refreshed!");
      },
      (error) => {
        console.error("❌ Refresh failed:", error);

        if (
          error.status === 401 &&
          error.error &&
          (error.error.message === 'Refresh token has expired' || error.error.message === 'Invalid refresh token')
        ) {
          //alert("⚠️ Your session has expired. Please log in again.");

          // Clear cookies manually (if needed)
          this.clearTokens();

          // Redirect to login
          this.router.navigate(['/auth']);
        }
      }
    );
  }


  

  logout(): Observable<any> {
    console.log("πŸ”§ Sending logout request with credentials");

    return this.http.post(`${this.apiUrl}/logout`, {}, { withCredentials: true }).pipe(
      tap(response => {
        console.log('πŸ”™ Response from backend:', response);
        this.clearTokens();
        this.clearAutoRefresh();  // βœ… Stop auto-refresh
        this.setLoggedIn(false);  // βœ… Reflect logout in UI
      }),
      catchError(error => {
        console.error('❌ Error from backend:', error);
        // Still ensure local state reflects logout
        this.clearTokens();
        this.clearAutoRefresh();
        this.setLoggedIn(false);
        return throwError(() => error);
      })
    );
  }



 



  clearTokens(): void {
    document.cookie = 'access_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    document.cookie = 'refresh_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    this.clearAutoRefresh();  // βœ…
  }


  //// βœ… Check if user is logged in (check for presence of cookies)
  //isLoggedIn(): boolean {
  //  // Check cookies directly (this will happen automatically when the browser sends cookies)
  //  // Check if the cookies are present (you can do it manually using a service or via backend)
  //  return document.cookie.includes('access_token');
  //}

  // βœ… Get access token (using cookies)
  getAccessToken(): string | null {
    const cookies = document.cookie.split('; ');
    for (let cookie of cookies) {
      if (cookie.startsWith('access_token=')) {
        return cookie.split('=')[1];
      }
    }
    return null;
  }

  // βœ… Save tokens (Not necessary, as tokens are managed via cookies)
  saveTokens(accessToken: string, refreshToken: string): void {
    // No need for this if you're using cookies, but if you want to persist in localStorage, use:
    localStorage.setItem('access_token', accessToken);
    localStorage.setItem('refresh_token', refreshToken);
  }

  //checkSession(): Observable<boolean> {
  //  return this.http.get(`${this.apiUrl}/check-auth`, { withCredentials: true }).pipe(
  //    tap((res: any) => {
  //      console.log('βœ… Session valid:', res);
  //      this.setLoggedIn(true);
  //    }),
  //    catchError((err) => {
  //      console.warn('❌ Session check failed:', err);
  //      this.setLoggedIn(false);
  //      return [false]; // Return false on error
  //    })
  //  );
  //}

  checkSession(): Observable<boolean> {
    return this.http.get(`${this.apiUrl}/check-auth`, { withCredentials: true }).pipe(
      tap((res: any) => {
        console.log('βœ… Session valid:', res);
        this.setLoggedIn(true);
        this.startAutoRefresh();
        return true; // βœ… Important!
      }),
      catchError((err) => {
        if (err.status === 401) {
          // Access token may be expired. Try refresh
          console.warn('πŸ”„ Access token expired. Trying to refresh...');

          return this.http.post(`${this.apiUrl}/refresh`, {}, { withCredentials: true }).pipe(
            tap((refreshRes: any) => {
              console.log("βœ… Token refreshed during checkSession.");
              //alert("βœ… Token refreshed during checkSession.");
              this.setLoggedIn(true);
              this.startAutoRefresh();
            }),
            catchError((refreshErr) => {
              console.error("❌ Refresh token failed during checkSession.", refreshErr);
              this.setLoggedIn(false);
              return of(false);
            })
          );
        } else {
          console.error("❌ Unknown error during checkSession", err);
          this.setLoggedIn(false);
          return of(false);
        }
      })
    );
  }




 



}