Ananthakr1shnan commited on
Commit
04daea4
·
verified ·
1 Parent(s): 141e89b

Update src/templates/login.html

Browse files
Files changed (1) hide show
  1. src/templates/login.html +255 -209
src/templates/login.html CHANGED
@@ -1,209 +1,255 @@
1
- {% extends "auth_base.html" %}
2
-
3
- {% block title %}ResearchMate - Login{% endblock %}
4
-
5
- {% block content %}
6
- <div class="row min-vh-100 justify-content-center align-items-center">
7
- <div class="col-md-6 col-lg-4">
8
- <div class="card shadow-lg">
9
- <div class="card-body p-5">
10
- <div class="text-center mb-4">
11
- <i class="fas fa-user-lock fa-3x text-primary mb-3"></i>
12
- <h3 class="text-primary-custom">Welcome to ResearchMate</h3>
13
- <p class="text-muted">Please log in to access your research projects</p>
14
- </div>
15
- <form id="login-form">
16
- <div class="mb-3">
17
- <label for="username" class="form-label">Username</label>
18
- <input type="text" class="form-control" id="username" name="username" required>
19
- </div>
20
- <div class="mb-3">
21
- <label for="password" class="form-label">Password</label>
22
- <input type="password" class="form-control" id="password" name="password" required>
23
- </div>
24
- <div class="d-grid">
25
- <button type="submit" class="btn btn-primary">
26
- <i class="fas fa-sign-in-alt me-2"></i>Login
27
- </button>
28
- </div>
29
- </form>
30
- <div class="text-center mt-4">
31
- <p class="text-muted">
32
- Don't have an account?
33
- <a href="#" class="text-primary" data-bs-toggle="modal" data-bs-target="#registerModal">Register here</a>
34
- </p>
35
- </div>
36
- </div>
37
- </div>
38
- </div>
39
- </div>
40
-
41
- <!-- Register Modal -->
42
- <div class="modal fade" id="registerModal" tabindex="-1">
43
- <div class="modal-dialog">
44
- <div class="modal-content">
45
- <div class="modal-header">
46
- <h5 class="modal-title">
47
- <i class="fas fa-user-plus me-2"></i><span style="color: #000;">Create Account</span>
48
- </h5>
49
- <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
50
- </div>
51
- <div class="modal-body">
52
- <form id="register-form">
53
- <div class="mb-3">
54
- <label for="reg-username" class="form-label">Username</label>
55
- <input type="text" class="form-control bg-white text-dark" id="reg-username" name="username" required>
56
- </div>
57
- <div class="mb-3">
58
- <label for="reg-email" class="form-label">Email</label>
59
- <input type="email" class="form-control bg-white text-dark" id="reg-email" name="email" required>
60
- </div>
61
- <div class="mb-3">
62
- <label for="reg-password" class="form-label">Password</label>
63
- <input type="password" class="form-control bg-white text-dark" id="reg-password" name="password" required>
64
- </div>
65
- <div class="mb-3">
66
- <label for="reg-confirm-password" class="form-label">Confirm Password</label>
67
- <input type="password" class="form-control bg-white text-dark" id="reg-confirm-password" name="confirm_password" required>
68
- </div>
69
- </form>
70
- </div>
71
- <div class="modal-footer">
72
- <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
73
- <button type="submit" form="register-form" class="btn btn-primary">
74
- <i class="fas fa-user-plus me-2"></i>Create Account
75
- </button>
76
- </div>
77
- </div>
78
- </div>
79
- </div>
80
- {% endblock %}
81
-
82
- {% block extra_js %}
83
- <script>
84
- // Include authentication utilities
85
- function setAuthToken(token) {
86
- // Store in sessionStorage for better security (clears on browser close)
87
- sessionStorage.setItem('authToken', token);
88
- // Also store in localStorage for compatibility, but with shorter expiry
89
- localStorage.setItem('authToken', token);
90
- localStorage.setItem('tokenTimestamp', Date.now().toString());
91
-
92
- // Set cookie with HttpOnly equivalent behavior
93
- document.cookie = `authToken=${token}; path=/; SameSite=Strict; Secure=${location.protocol === 'https:'}`;
94
- }
95
-
96
- document.addEventListener('DOMContentLoaded', function() {
97
- const loginForm = document.getElementById('login-form');
98
- const registerForm = document.getElementById('register-form');
99
-
100
- // Login handler
101
- loginForm.addEventListener('submit', function(e) {
102
- e.preventDefault();
103
-
104
- const username = document.getElementById('username').value;
105
- const password = document.getElementById('password').value;
106
-
107
- fetch('/api/auth/login', {
108
- method: 'POST',
109
- headers: {
110
- 'Content-Type': 'application/json',
111
- },
112
- body: JSON.stringify({
113
- username: username,
114
- password: password
115
- })
116
- })
117
- .then(response => response.json())
118
- .then(data => {
119
- if (data.success) {
120
- // Use secure token storage
121
- setAuthToken(data.token);
122
- sessionStorage.setItem('userId', data.user_id);
123
- localStorage.setItem('userId', data.user_id);
124
-
125
- // Show success message
126
- showAlert('success', 'Login successful! Redirecting...');
127
-
128
- // Redirect to home page after a short delay
129
- setTimeout(() => {
130
- window.location.href = '/';
131
- }, 1000);
132
- } else {
133
- showAlert('danger', data.error || 'Login failed');
134
- }
135
- })
136
- .catch(error => {
137
- showAlert('danger', 'Network error: ' + error.message);
138
- });
139
- });
140
-
141
- // Register handler
142
- registerForm.addEventListener('submit', function(e) {
143
- e.preventDefault();
144
-
145
- const username = document.getElementById('reg-username').value;
146
- const email = document.getElementById('reg-email').value;
147
- const password = document.getElementById('reg-password').value;
148
- const confirmPassword = document.getElementById('reg-confirm-password').value;
149
-
150
- if (password !== confirmPassword) {
151
- showAlert('danger', 'Passwords do not match');
152
- return;
153
- }
154
-
155
- fetch('/api/auth/register', {
156
- method: 'POST',
157
- headers: {
158
- 'Content-Type': 'application/json',
159
- },
160
- body: JSON.stringify({
161
- username: username,
162
- email: email,
163
- password: password
164
- })
165
- })
166
- .then(response => response.json())
167
- .then(data => {
168
- if (data.success) {
169
- const modal = bootstrap.Modal.getInstance(document.getElementById('registerModal'));
170
- modal.hide();
171
- showAlert('success', 'Account created successfully! Please log in.');
172
- registerForm.reset();
173
- } else {
174
- showAlert('danger', data.error || 'Registration failed');
175
- }
176
- })
177
- .catch(error => {
178
- showAlert('danger', 'Network error: ' + error.message);
179
- });
180
- });
181
-
182
- function showAlert(type, message) {
183
- const alert = document.createElement('div');
184
- alert.className = `alert alert-${type} alert-dismissible fade show`;
185
- alert.innerHTML = `
186
- <i class="fas fa-${type === 'success' ? 'check' : 'exclamation-triangle'} me-2"></i>
187
- ${message}
188
- <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
189
- `;
190
-
191
- // Try to insert into .container, else fallback to main content
192
- const container = document.querySelector('.container');
193
- if (container) {
194
- container.insertBefore(alert, container.firstChild);
195
- } else {
196
- // Fallback: insert at top of main content
197
- const main = document.querySelector('main') || document.body;
198
- main.insertBefore(alert, main.firstChild);
199
- }
200
-
201
- setTimeout(() => {
202
- if (alert.parentNode) {
203
- alert.remove();
204
- }
205
- }, 5000);
206
- }
207
- });
208
- </script>
209
- {% endblock %}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {% extends "auth_base.html" %}
2
+
3
+ {% block title %}ResearchMate - Login{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="row min-vh-100 justify-content-center align-items-center">
7
+ <div class="col-md-6 col-lg-4">
8
+ <div class="card shadow-lg">
9
+ <div class="card-body p-5">
10
+ <div class="text-center mb-4">
11
+ <i class="fas fa-user-lock fa-3x text-primary mb-3"></i>
12
+ <h3 class="text-primary-custom">Welcome to ResearchMate</h3>
13
+ <p class="text-muted">Please log in to access your research projects</p>
14
+ </div>
15
+
16
+ <!-- Alert container for messages -->
17
+ <div id="alert-container"></div>
18
+
19
+ <form id="login-form">
20
+ <div class="mb-3">
21
+ <label for="username" class="form-label">Username</label>
22
+ <input type="text" class="form-control" id="username" name="username" required>
23
+ </div>
24
+ <div class="mb-3">
25
+ <label for="password" class="form-label">Password</label>
26
+ <input type="password" class="form-control" id="password" name="password" required>
27
+ </div>
28
+ <div class="d-grid">
29
+ <button type="submit" class="btn btn-primary" id="login-btn">
30
+ <i class="fas fa-sign-in-alt me-2"></i>Login
31
+ </button>
32
+ </div>
33
+ </form>
34
+ <div class="text-center mt-4">
35
+ <p class="text-muted">
36
+ Don't have an account?
37
+ <a href="#" class="text-primary" data-bs-toggle="modal" data-bs-target="#registerModal">Register here</a>
38
+ </p>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+
45
+ <!-- Register Modal -->
46
+ <div class="modal fade" id="registerModal" tabindex="-1">
47
+ <div class="modal-dialog">
48
+ <div class="modal-content">
49
+ <div class="modal-header">
50
+ <h5 class="modal-title">
51
+ <i class="fas fa-user-plus me-2"></i><span style="color: #000;">Create Account</span>
52
+ </h5>
53
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
54
+ </div>
55
+ <div class="modal-body">
56
+ <form id="register-form">
57
+ <div class="mb-3">
58
+ <label for="reg-username" class="form-label">Username</label>
59
+ <input type="text" class="form-control bg-white text-dark" id="reg-username" name="username" required>
60
+ </div>
61
+ <div class="mb-3">
62
+ <label for="reg-email" class="form-label">Email</label>
63
+ <input type="email" class="form-control bg-white text-dark" id="reg-email" name="email" required>
64
+ </div>
65
+ <div class="mb-3">
66
+ <label for="reg-password" class="form-label">Password</label>
67
+ <input type="password" class="form-control bg-white text-dark" id="reg-password" name="password" required>
68
+ </div>
69
+ <div class="mb-3">
70
+ <label for="reg-confirm-password" class="form-label">Confirm Password</label>
71
+ <input type="password" class="form-control bg-white text-dark" id="reg-confirm-password" name="confirm_password" required>
72
+ </div>
73
+ </form>
74
+ </div>
75
+ <div class="modal-footer">
76
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
77
+ <button type="submit" form="register-form" class="btn btn-primary">
78
+ <i class="fas fa-user-plus me-2"></i>Create Account
79
+ </button>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ {% endblock %}
85
+
86
+ {% block extra_js %}
87
+ <script>
88
+ document.addEventListener('DOMContentLoaded', function() {
89
+ const loginForm = document.getElementById('login-form');
90
+ const registerForm = document.getElementById('register-form');
91
+ const loginBtn = document.getElementById('login-btn');
92
+
93
+ // Login handler
94
+ loginForm.addEventListener('submit', async function(e) {
95
+ e.preventDefault();
96
+
97
+ const username = document.getElementById('username').value.trim();
98
+ const password = document.getElementById('password').value;
99
+
100
+ if (!username || !password) {
101
+ showAlert('danger', 'Please fill in all fields');
102
+ return;
103
+ }
104
+
105
+ // Show loading state
106
+ const originalBtnText = loginBtn.innerHTML;
107
+ loginBtn.disabled = true;
108
+ loginBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Logging in...';
109
+
110
+ try {
111
+ const response = await fetch('/api/auth/login', {
112
+ method: 'POST',
113
+ headers: {
114
+ 'Content-Type': 'application/json',
115
+ },
116
+ credentials: 'include', // Important: Include cookies
117
+ body: JSON.stringify({
118
+ username: username,
119
+ password: password
120
+ })
121
+ });
122
+
123
+ const data = await response.json();
124
+
125
+ if (response.ok && data.success) {
126
+ // Store token as backup
127
+ localStorage.setItem('authToken', data.token);
128
+ localStorage.setItem('userId', data.user_id);
129
+ localStorage.setItem('username', data.username);
130
+
131
+ // Show success message
132
+ showAlert('success', 'Login successful! Redirecting...');
133
+
134
+ // Redirect after short delay
135
+ setTimeout(() => {
136
+ window.location.href = data.redirect_url || '/';
137
+ }, 1500);
138
+ } else {
139
+ showAlert('danger', data.detail || data.error || 'Login failed. Please try again.');
140
+ }
141
+ } catch (error) {
142
+ console.error('Login error:', error);
143
+ showAlert('danger', 'Network error. Please check your connection and try again.');
144
+ } finally {
145
+ // Reset button state
146
+ loginBtn.disabled = false;
147
+ loginBtn.innerHTML = originalBtnText;
148
+ }
149
+ });
150
+
151
+ // Register handler
152
+ registerForm.addEventListener('submit', async function(e) {
153
+ e.preventDefault();
154
+
155
+ const username = document.getElementById('reg-username').value.trim();
156
+ const email = document.getElementById('reg-email').value.trim();
157
+ const password = document.getElementById('reg-password').value;
158
+ const confirmPassword = document.getElementById('reg-confirm-password').value;
159
+
160
+ if (!username || !email || !password || !confirmPassword) {
161
+ showAlert('danger', 'Please fill in all fields');
162
+ return;
163
+ }
164
+
165
+ if (password !== confirmPassword) {
166
+ showAlert('danger', 'Passwords do not match');
167
+ return;
168
+ }
169
+
170
+ if (password.length < 6) {
171
+ showAlert('danger', 'Password must be at least 6 characters long');
172
+ return;
173
+ }
174
+
175
+ try {
176
+ const response = await fetch('/api/auth/register', {
177
+ method: 'POST',
178
+ headers: {
179
+ 'Content-Type': 'application/json',
180
+ },
181
+ body: JSON.stringify({
182
+ username: username,
183
+ email: email,
184
+ password: password
185
+ })
186
+ });
187
+
188
+ const data = await response.json();
189
+
190
+ if (response.ok && data.success) {
191
+ const modal = bootstrap.Modal.getInstance(document.getElementById('registerModal'));
192
+ modal.hide();
193
+ showAlert('success', 'Account created successfully! Please log in.');
194
+ registerForm.reset();
195
+ } else {
196
+ showAlert('danger', data.detail || data.error || 'Registration failed. Please try again.');
197
+ }
198
+ } catch (error) {
199
+ console.error('Registration error:', error);
200
+ showAlert('danger', 'Network error. Please check your connection and try again.');
201
+ }
202
+ });
203
+
204
+ function showAlert(type, message) {
205
+ const alertContainer = document.getElementById('alert-container');
206
+
207
+ // Clear existing alerts
208
+ alertContainer.innerHTML = '';
209
+
210
+ const alert = document.createElement('div');
211
+ alert.className = `alert alert-${type} alert-dismissible fade show`;
212
+ alert.innerHTML = `
213
+ <i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-triangle'} me-2"></i>
214
+ ${message}
215
+ <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
216
+ `;
217
+
218
+ alertContainer.appendChild(alert);
219
+
220
+ // Auto-remove after 5 seconds for error messages
221
+ if (type === 'danger') {
222
+ setTimeout(() => {
223
+ if (alert.parentNode) {
224
+ alert.remove();
225
+ }
226
+ }, 5000);
227
+ }
228
+ }
229
+
230
+ // Check if user is already logged in
231
+ const token = localStorage.getItem('authToken');
232
+ if (token) {
233
+ // Verify token is still valid
234
+ fetch('/api/user/status', {
235
+ headers: {
236
+ 'Authorization': `Bearer ${token}`
237
+ },
238
+ credentials: 'include'
239
+ })
240
+ .then(response => {
241
+ if (response.ok) {
242
+ // User is already logged in, redirect
243
+ window.location.href = '/';
244
+ }
245
+ })
246
+ .catch(() => {
247
+ // Token is invalid, clear it
248
+ localStorage.removeItem('authToken');
249
+ localStorage.removeItem('userId');
250
+ localStorage.removeItem('username');
251
+ });
252
+ }
253
+ });
254
+ </script>
255
+ {% endblock %}