ashrithagowthami commited on
Commit
ae1a7c8
·
verified ·
1 Parent(s): b8f94df

Upload 5 files

Browse files
Files changed (4) hide show
  1. database.sqlite +0 -0
  2. server.py +35 -1
  3. student-login.html +69 -0
  4. teacher-login.html +75 -0
database.sqlite CHANGED
Binary files a/database.sqlite and b/database.sqlite differ
 
server.py CHANGED
@@ -30,8 +30,14 @@ def init_db():
30
  c.execute('''CREATE TABLE IF NOT EXISTS users (
31
  id text PRIMARY KEY, email text, name text, role text,
32
  roll_number text, department text, institution text,
33
- is_active boolean, face_data text, last_login datetime
 
34
  )''')
 
 
 
 
 
35
  c.execute('''CREATE TABLE IF NOT EXISTS sessions (
36
  id text PRIMARY KEY, teacher_id text, subject text,
37
  qr_code text, qr_expires_at datetime, geofence_lat real,
@@ -206,6 +212,34 @@ async def handle_item(table_name: str, item_id: str, request: Request):
206
  raise HTTPException(status_code=404, detail="Item not found")
207
  return {"success": True}
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  # Mount static files correctly
210
  # This should happen LAST so API routes take precedence
211
  app.mount("/", StaticFiles(directory=".", html=True), name="static")
 
30
  c.execute('''CREATE TABLE IF NOT EXISTS users (
31
  id text PRIMARY KEY, email text, name text, role text,
32
  roll_number text, department text, institution text,
33
+ is_active boolean, face_data text, last_login datetime,
34
+ password text
35
  )''')
36
+ # Use try-except to add password column if it doesn't exist (for existing databases)
37
+ try:
38
+ c.execute("ALTER TABLE users ADD COLUMN password text")
39
+ except:
40
+ pass
41
  c.execute('''CREATE TABLE IF NOT EXISTS sessions (
42
  id text PRIMARY KEY, teacher_id text, subject text,
43
  qr_code text, qr_expires_at datetime, geofence_lat real,
 
212
  raise HTTPException(status_code=404, detail="Item not found")
213
  return {"success": True}
214
 
215
+ @app.post("/login")
216
+ async def login(request: Request):
217
+ data = await request.json()
218
+ email = data.get("email", "").lower()
219
+ password = data.get("password", "")
220
+
221
+ conn = get_db()
222
+ conn.row_factory = dict_factory
223
+ c = conn.cursor()
224
+
225
+ # Query user by email
226
+ c.execute("SELECT * FROM users WHERE LOWER(email) = ?", (email,))
227
+ user = c.fetchone()
228
+
229
+ if not user:
230
+ raise HTTPException(status_code=404, detail="User not found")
231
+
232
+ if user.get("password") != password:
233
+ raise HTTPException(status_code=401, detail="Invalid password")
234
+
235
+ if not user.get("is_active"):
236
+ raise HTTPException(status_code=403, detail="Account deactivated")
237
+
238
+ # Exclude password from response
239
+ user_data = dict(user)
240
+ user_data.pop("password", None)
241
+ return user_data
242
+
243
  # Mount static files correctly
244
  # This should happen LAST so API routes take precedence
245
  app.mount("/", StaticFiles(directory=".", html=True), name="static")
student-login.html CHANGED
@@ -77,6 +77,25 @@
77
  <div id="googleBtnContainer"></div>
78
  </div>
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  <!-- Loading State -->
81
  <div id="loadingState" class="auth-loading hidden">
82
  <div class="spinner spinner-dark"></div>
@@ -262,6 +281,56 @@
262
  }
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  // Google OAuth callback
266
  function handleGoogleCredential(response) {
267
  try {
 
77
  <div id="googleBtnContainer"></div>
78
  </div>
79
 
80
+ <div class="auth-divider">
81
+ <span>OR</span>
82
+ </div>
83
+
84
+ <!-- Direct Email/Password Login -->
85
+ <div id="emailLoginForm">
86
+ <div class="form-group">
87
+ <label class="form-label">Institution Email</label>
88
+ <input type="email" id="emailInput" class="form-control" placeholder="your@cbit.org.in">
89
+ </div>
90
+ <div class="form-group">
91
+ <label class="form-label">Password</label>
92
+ <input type="password" id="passwordInput" class="form-control" placeholder="••••••••">
93
+ </div>
94
+ <button class="btn btn-primary btn-full" onclick="loginWithEmail()">
95
+ Login with Email
96
+ </button>
97
+ </div>
98
+
99
  <!-- Loading State -->
100
  <div id="loadingState" class="auth-loading hidden">
101
  <div class="spinner spinner-dark"></div>
 
281
  }
282
  }
283
 
284
+ async function loginWithEmail() {
285
+ const email = document.getElementById('emailInput').value.trim();
286
+ const password = document.getElementById('passwordInput').value;
287
+
288
+ if (!email || !password) {
289
+ showAlert('Please enter both email and password.');
290
+ return;
291
+ }
292
+
293
+ try {
294
+ showLoading('Verifying credentials...');
295
+
296
+ const response = await fetch('/login', {
297
+ method: 'POST',
298
+ headers: { 'Content-Type': 'application/json' },
299
+ body: JSON.stringify({ email, password })
300
+ });
301
+
302
+ if (!response.ok) {
303
+ const err = await response.json();
304
+ throw new Error(err.detail || 'Login failed');
305
+ }
306
+
307
+ const user = await response.json();
308
+
309
+ // Ensure it's a student
310
+ if (user.role !== 'student') {
311
+ showAlert(`Unauthorized: Registered as "${user.role}"`);
312
+ hideLoading();
313
+ return;
314
+ }
315
+
316
+ const sessionUser = {
317
+ ...user,
318
+ picture: user.picture || `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=4F46E5&color=fff`
319
+ };
320
+
321
+ AuthState.save(sessionUser);
322
+ await Logger.log('LOGIN_SUCCESS_EMAIL', 'auth', { email, role: 'student' }, 'success');
323
+
324
+ showWelcome(sessionUser);
325
+ setTimeout(() => { window.location.href = 'student-dashboard.html'; }, 1800);
326
+
327
+ } catch (err) {
328
+ console.error('Login error:', err);
329
+ hideLoading();
330
+ showAlert(err.message === 'User not found' ? 'Email not registered.' : 'Invalid password or account error.');
331
+ }
332
+ }
333
+
334
  // Google OAuth callback
335
  function handleGoogleCredential(response) {
336
  try {
teacher-login.html CHANGED
@@ -69,6 +69,25 @@
69
  <div id="googleBtnContainer"></div>
70
  </div>
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  <div id="loadingState" class="auth-loading hidden">
73
  <div class="spinner spinner-dark"></div>
74
  <span id="loadingText">Verifying faculty credentials...</span>
@@ -214,6 +233,62 @@
214
  }
215
  }
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  function handleGoogleCredential(response) {
218
  try {
219
  const parts = response.credential.split('.');
 
69
  <div id="googleBtnContainer"></div>
70
  </div>
71
 
72
+ <div class="auth-divider">
73
+ <span>OR</span>
74
+ </div>
75
+
76
+ <!-- Direct Email/Password Login -->
77
+ <div id="emailLoginForm">
78
+ <div class="form-group">
79
+ <label class="form-label">Institution Email</label>
80
+ <input type="email" id="emailInput" class="form-control" placeholder="teacher@cbit.org.in">
81
+ </div>
82
+ <div class="form-group">
83
+ <label class="form-label">Password</label>
84
+ <input type="password" id="passwordInput" class="form-control" placeholder="••••••••">
85
+ </div>
86
+ <button class="btn btn-primary btn-full" onclick="loginWithEmail()">
87
+ Login with Email
88
+ </button>
89
+ </div>
90
+
91
  <div id="loadingState" class="auth-loading hidden">
92
  <div class="spinner spinner-dark"></div>
93
  <span id="loadingText">Verifying faculty credentials...</span>
 
233
  }
234
  }
235
 
236
+ async function loginWithEmail() {
237
+ const email = document.getElementById('emailInput').value.trim();
238
+ const password = document.getElementById('passwordInput').value;
239
+
240
+ if (!email || !password) {
241
+ showAlert('Please enter both email and password.');
242
+ return;
243
+ }
244
+
245
+ try {
246
+ showLoading('Verifying credentials...');
247
+
248
+ const response = await fetch('/login', {
249
+ method: 'POST',
250
+ headers: { 'Content-Type': 'application/json' },
251
+ body: JSON.stringify({ email, password })
252
+ });
253
+
254
+ if (!response.ok) {
255
+ const err = await response.json();
256
+ throw new Error(err.detail || 'Login failed');
257
+ }
258
+
259
+ const user = await response.json();
260
+
261
+ // Ensure it's faculty/admin
262
+ if (user.role !== 'teacher' && user.role !== 'admin') {
263
+ showAlert(`Unauthorized: Registered as "${user.role}"`);
264
+ hideLoading();
265
+ return;
266
+ }
267
+
268
+ const sessionUser = {
269
+ ...user,
270
+ picture: user.picture || `https://ui-avatars.com/api/?name=${encodeURIComponent(user.name)}&background=10B981&color=fff`
271
+ };
272
+
273
+ AuthState.save(sessionUser);
274
+ await Logger.log('LOGIN_SUCCESS_EMAIL', 'auth', { email, role: user.role }, 'success');
275
+
276
+ document.getElementById('loginCard').classList.add('hidden');
277
+ document.getElementById('welcomeCard').classList.remove('hidden');
278
+ document.getElementById('welcomeAvatar').src = sessionUser.picture;
279
+ document.getElementById('welcomeName').textContent = sessionUser.email;
280
+
281
+ setTimeout(() => {
282
+ window.location.href = user.role === 'admin' ? 'admin-panel.html' : 'teacher-dashboard.html';
283
+ }, 1800);
284
+
285
+ } catch (err) {
286
+ console.error('Login error:', err);
287
+ hideLoading();
288
+ showAlert(err.message === 'User not found' ? 'Email not registered.' : 'Invalid password or account error.');
289
+ }
290
+ }
291
+
292
  function handleGoogleCredential(response) {
293
  try {
294
  const parts = response.credential.split('.');