webcodelab commited on
Commit
4aaeb2d
·
verified ·
1 Parent(s): 39fb762

Update app/routes.py

Browse files
Files changed (1) hide show
  1. app/routes.py +165 -62
app/routes.py CHANGED
@@ -4,14 +4,22 @@ from flask import Blueprint, render_template, request, redirect, url_for, flash,
4
  from .email_utils import send_verification_email
5
  from .code_generator import generate_ranker_code
6
  from .utils import rank_resumes_by_similarity
7
- import requests
8
  from werkzeug.utils import secure_filename
9
  from .ranker import rank_resumes_by_semantic_similarity
10
  import traceback
11
  from werkzeug.security import generate_password_hash, check_password_hash
12
  from .supabase_client import get_user_by_email, create_user
13
- import os
14
  import uuid
 
 
 
 
 
 
 
 
 
15
 
16
 
17
  auth = Blueprint('auth', __name__)
@@ -28,17 +36,30 @@ def embed():
28
 
29
 
30
 
 
 
31
  @auth.route('/rank-resumes', methods=['POST'])
32
  def rank_resumes():
33
  auth_header = request.headers.get('Authorization')
34
  if not auth_header or not auth_header.startswith('Bearer '):
35
  return jsonify({"error": "Missing or invalid Authorization header"}), 401
36
 
37
- api_key = auth_header.split(" ")[1]
38
- user = User.query.filter_by(api_key=api_key).first()
39
- if not user:
 
 
 
 
 
 
 
 
 
 
40
  return jsonify({"error": "Invalid API key"}), 403
41
 
 
42
  resumes = request.files.getlist('resumes')
43
  job_description = request.form.get('job_description')
44
 
@@ -55,6 +76,7 @@ def rank_resumes():
55
 
56
 
57
 
 
58
  auth = Blueprint('auth', __name__)
59
 
60
 
@@ -104,21 +126,39 @@ def login():
104
  if request.method == 'POST':
105
  email = request.form['email']
106
  password = request.form['password']
107
- user = User.query.filter_by(email=email).first()
108
 
109
- if user and user.check_password(password):
110
- if not user.is_verified:
111
- flash('Please verify your email before logging in.')
112
- return redirect(url_for('auth.login'))
 
 
 
 
 
113
 
114
- session['user_id'] = user.id
115
- session['username'] = user.username
116
- flash('Logged in successfully.')
117
- return redirect(url_for('auth.dashboard'))
118
- else:
 
 
 
119
  flash('Invalid email or password.')
120
  return redirect(url_for('auth.login'))
121
 
 
 
 
 
 
 
 
 
 
 
 
122
  return render_template('login.html')
123
 
124
  @auth.route('/resend-verification', methods=['GET', 'POST'])
@@ -126,43 +166,79 @@ def resend_verification():
126
  if request.method == 'POST':
127
  try:
128
  email = request.form['email']
129
- user = User.query.filter_by(email=email).first()
130
-
131
- if user:
132
- if user.is_verified:
133
- flash('Your email is already verified. You can log in.')
134
- return redirect(url_for('auth.login'))
135
-
136
- user.generate_verification_token()
137
- db.session.commit()
138
-
139
- result = send_verification_email(user.email, user.username, user.verification_token)
140
- if result is True:
141
- flash('Verification email resent. Please check your inbox.')
142
- else:
143
- print(" Email error from resend:", result)
144
- return jsonify(result), 500 # Shows JSON error in browser
145
- else:
146
  flash('No account found with that email.')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  return redirect(url_for('auth.login'))
149
 
150
  except Exception as e:
151
- print(" Resend error:", e)
152
  traceback.print_exc()
153
  return jsonify({"error": str(e)}), 500
154
 
155
  return render_template('resend_verification.html')
156
 
 
157
  @auth.route('/dashboard')
158
  def dashboard():
159
  if 'user_id' not in session:
160
  flash('Please log in to access the dashboard.')
161
  return redirect(url_for('auth.login'))
162
 
163
- user = User.query.get(session['user_id'])
 
 
 
 
 
 
 
 
 
 
164
  return render_template('dashboard.html', user=user)
165
 
 
166
  @auth.route('/generate-api', methods=['GET', 'POST'])
167
  def generate_api():
168
  if 'user_id' not in session:
@@ -181,10 +257,21 @@ def regenerate_api_key():
181
  flash('Please log in.')
182
  return redirect(url_for('auth.login'))
183
 
184
- user = User.query.get(session['user_id'])
185
- user.generate_api_key()
186
- db.session.commit()
187
- flash('API key regenerated.')
 
 
 
 
 
 
 
 
 
 
 
188
  return redirect(url_for('auth.dashboard'))
189
 
190
  @auth.route('/logout')
@@ -195,26 +282,37 @@ def logout():
195
 
196
  @auth.route('/verify/<token>')
197
  def verify_email(token):
198
- user = User.query.filter_by(verification_token=token).first()
199
- if user:
200
- user.is_verified = True
201
- user.verification_token = None
202
- db.session.commit()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  flash('Email verified! You can now log in.')
204
  return redirect(url_for('auth.login'))
205
  else:
206
- flash('Invalid or expired verification link.')
207
  return redirect(url_for('auth.register'))
208
 
 
 
209
  @auth.route('/docs')
210
  def docs():
211
  return render_template('docs.html', response=None)
212
 
213
- # Inside your auth.py or views.py
214
-
215
- from flask import request, render_template, redirect, url_for, flash
216
- from .models import User
217
- from .utils import rank_resumes_by_similarity # import your real function
218
 
219
  @auth.route('/try-api', methods=['POST'])
220
  def try_api():
@@ -226,19 +324,18 @@ def try_api():
226
  flash("All fields are required.")
227
  return redirect(url_for('auth.docs'))
228
 
229
- user = User.query.filter_by(api_key=api_key).first()
230
- if not user:
 
 
 
 
 
231
  return render_template('docs.html', response=" Invalid API key.")
232
 
233
  try:
234
- # Use the actual ranking logic
235
- results = rank_resumes_by_semantic_similarity(resumes, job_description)
236
-
237
- return render_template(
238
- 'docs.html',
239
- response=results,
240
- job_description=job_description
241
- )
242
  except Exception as e:
243
  return render_template('docs.html', response=f" Error: {str(e)}")
244
 
@@ -248,9 +345,15 @@ def try_api():
248
  @auth.route('/ping-db')
249
  def ping_db():
250
  try:
251
- # Try to count users in the database
252
- count = User.query.count()
253
- return f" Connected to DB. Users count: {count}"
 
 
 
 
 
 
254
  except Exception as e:
255
  return f" DB Error: {e}"
256
 
 
4
  from .email_utils import send_verification_email
5
  from .code_generator import generate_ranker_code
6
  from .utils import rank_resumes_by_similarity
 
7
  from werkzeug.utils import secure_filename
8
  from .ranker import rank_resumes_by_semantic_similarity
9
  import traceback
10
  from werkzeug.security import generate_password_hash, check_password_hash
11
  from .supabase_client import get_user_by_email, create_user
12
+ import os, requests
13
  import uuid
14
+ from .supabase_config import SUPABASE_URL, SUPABASE_API_KEY
15
+
16
+ SUPABASE_URL = os.getenv("SUPABASE_URL")
17
+ SUPABASE_API_KEY = os.getenv("SUPABASE_API_KEY")
18
+ HEADERS = {
19
+ "apikey": SUPABASE_API_KEY,
20
+ "Authorization": f"Bearer {SUPABASE_API_KEY}",
21
+ "Content-Type": "application/json"
22
+ }
23
 
24
 
25
  auth = Blueprint('auth', __name__)
 
36
 
37
 
38
 
39
+
40
+
41
  @auth.route('/rank-resumes', methods=['POST'])
42
  def rank_resumes():
43
  auth_header = request.headers.get('Authorization')
44
  if not auth_header or not auth_header.startswith('Bearer '):
45
  return jsonify({"error": "Missing or invalid Authorization header"}), 401
46
 
47
+ api_key = auth_header.split(" ")[1].strip()
48
+
49
+ # Supabase: Check user by API key
50
+ headers = {
51
+ "apikey": SUPABASE_API_KEY,
52
+ "Authorization": f"Bearer {SUPABASE_API_KEY}"
53
+ }
54
+ user_check = requests.get(
55
+ f"{SUPABASE_URL}/rest/v1/users?api_key=eq.{api_key}",
56
+ headers=headers
57
+ )
58
+
59
+ if user_check.status_code != 200 or not user_check.json():
60
  return jsonify({"error": "Invalid API key"}), 403
61
 
62
+ # Proceed to ranking
63
  resumes = request.files.getlist('resumes')
64
  job_description = request.form.get('job_description')
65
 
 
76
 
77
 
78
 
79
+
80
  auth = Blueprint('auth', __name__)
81
 
82
 
 
126
  if request.method == 'POST':
127
  email = request.form['email']
128
  password = request.form['password']
 
129
 
130
+ # Query Supabase for user by email
131
+ headers = {
132
+ "apikey": SUPABASE_API_KEY,
133
+ "Authorization": f"Bearer {SUPABASE_API_KEY}"
134
+ }
135
+ response = requests.get(
136
+ f"{SUPABASE_URL}/rest/v1/users?email=eq.{email}",
137
+ headers=headers
138
+ )
139
 
140
+ if response.status_code != 200 or not response.json():
141
+ flash('Invalid email or password.')
142
+ return redirect(url_for('auth.login'))
143
+
144
+ user_data = response.json()[0]
145
+
146
+ # Check password
147
+ if not check_password_hash(user_data['password'], password):
148
  flash('Invalid email or password.')
149
  return redirect(url_for('auth.login'))
150
 
151
+ # Check if user is verified
152
+ if not user_data.get('is_verified', False):
153
+ flash('Please verify your email before logging in.')
154
+ return redirect(url_for('auth.login'))
155
+
156
+ # Login successful
157
+ session['user_id'] = user_data['id']
158
+ session['username'] = user_data['username']
159
+ flash('Logged in successfully.')
160
+ return redirect(url_for('auth.dashboard'))
161
+
162
  return render_template('login.html')
163
 
164
  @auth.route('/resend-verification', methods=['GET', 'POST'])
 
166
  if request.method == 'POST':
167
  try:
168
  email = request.form['email']
169
+
170
+ # 🔍 Fetch user by email
171
+ headers = {
172
+ "apikey": SUPABASE_API_KEY,
173
+ "Authorization": f"Bearer {SUPABASE_API_KEY}"
174
+ }
175
+ res = requests.get(
176
+ f"{SUPABASE_URL}/rest/v1/users?email=eq.{email}&select=*",
177
+ headers=headers
178
+ )
179
+
180
+ if res.status_code != 200 or not res.json():
 
 
 
 
 
181
  flash('No account found with that email.')
182
+ return redirect(url_for('auth.login'))
183
+
184
+ user = res.json()[0]
185
+
186
+ if user.get("is_verified") == True:
187
+ flash('Your email is already verified. You can log in.')
188
+ return redirect(url_for('auth.login'))
189
+
190
+ # Generate new token
191
+ new_token = str(uuid.uuid4())
192
+
193
+ # Update `email_token` in Supabase
194
+ patch_res = requests.patch(
195
+ f"{SUPABASE_URL}/rest/v1/users?email=eq.{email}",
196
+ headers={**headers, "Content-Type": "application/json"},
197
+ json={"email_token": new_token}
198
+ )
199
+
200
+ if patch_res.status_code != 204:
201
+ print("Failed to update token:", patch_res.text)
202
+ return jsonify({"error": "Failed to update verification token."}), 500
203
+
204
+ # Send the verification email
205
+ result = send_verification_email(user['email'], user['username'], new_token)
206
+ if result is True:
207
+ flash('Verification email resent. Please check your inbox.')
208
+ else:
209
+ print("Email error from resend:", result)
210
+ return jsonify(result), 500
211
 
212
  return redirect(url_for('auth.login'))
213
 
214
  except Exception as e:
215
+ print("Resend error:", e)
216
  traceback.print_exc()
217
  return jsonify({"error": str(e)}), 500
218
 
219
  return render_template('resend_verification.html')
220
 
221
+
222
  @auth.route('/dashboard')
223
  def dashboard():
224
  if 'user_id' not in session:
225
  flash('Please log in to access the dashboard.')
226
  return redirect(url_for('auth.login'))
227
 
228
+ user_id = session['user_id']
229
+ res = requests.get(
230
+ f"{SUPABASE_URL}/rest/v1/users?id=eq.{user_id}&select=*",
231
+ headers=HEADERS
232
+ )
233
+
234
+ if res.status_code != 200 or not res.json():
235
+ flash('User not found.')
236
+ return redirect(url_for('auth.login'))
237
+
238
+ user = res.json()[0]
239
  return render_template('dashboard.html', user=user)
240
 
241
+
242
  @auth.route('/generate-api', methods=['GET', 'POST'])
243
  def generate_api():
244
  if 'user_id' not in session:
 
257
  flash('Please log in.')
258
  return redirect(url_for('auth.login'))
259
 
260
+ new_api_key = str(uuid.uuid4())
261
+ user_id = session['user_id']
262
+
263
+ patch = requests.patch(
264
+ f"{SUPABASE_URL}/rest/v1/users?id=eq.{user_id}",
265
+ headers=HEADERS,
266
+ json={"api_key": new_api_key}
267
+ )
268
+
269
+ if patch.status_code == 204:
270
+ flash('API key regenerated.')
271
+ else:
272
+ print(" Failed to update API key:", patch.text)
273
+ flash('Failed to regenerate API key.')
274
+
275
  return redirect(url_for('auth.dashboard'))
276
 
277
  @auth.route('/logout')
 
282
 
283
  @auth.route('/verify/<token>')
284
  def verify_email(token):
285
+ res = requests.get(
286
+ f"{SUPABASE_URL}/rest/v1/users?email_token=eq.{token}&select=*",
287
+ headers=HEADERS
288
+ )
289
+
290
+ if res.status_code != 200 or not res.json():
291
+ flash('Invalid or expired verification link.')
292
+ return redirect(url_for('auth.register'))
293
+
294
+ user = res.json()[0]
295
+ email = user["email"]
296
+
297
+ patch = requests.patch(
298
+ f"{SUPABASE_URL}/rest/v1/users?email=eq.{email}",
299
+ headers=HEADERS,
300
+ json={"is_verified": True, "email_token": None}
301
+ )
302
+
303
+ if patch.status_code == 204:
304
  flash('Email verified! You can now log in.')
305
  return redirect(url_for('auth.login'))
306
  else:
307
+ flash('Verification failed.')
308
  return redirect(url_for('auth.register'))
309
 
310
+
311
+
312
  @auth.route('/docs')
313
  def docs():
314
  return render_template('docs.html', response=None)
315
 
 
 
 
 
 
316
 
317
  @auth.route('/try-api', methods=['POST'])
318
  def try_api():
 
324
  flash("All fields are required.")
325
  return redirect(url_for('auth.docs'))
326
 
327
+ # Validate API key from Supabase
328
+ res = requests.get(
329
+ f"{SUPABASE_URL}/rest/v1/users?api_key=eq.{api_key}&select=id",
330
+ headers=HEADERS
331
+ )
332
+
333
+ if res.status_code != 200 or not res.json():
334
  return render_template('docs.html', response=" Invalid API key.")
335
 
336
  try:
337
+ results = rank_resumes_by_similarity(resumes, job_description)
338
+ return render_template('docs.html', response=results, job_description=job_description)
 
 
 
 
 
 
339
  except Exception as e:
340
  return render_template('docs.html', response=f" Error: {str(e)}")
341
 
 
345
  @auth.route('/ping-db')
346
  def ping_db():
347
  try:
348
+ res = requests.get(
349
+ f"{SUPABASE_URL}/rest/v1/users?select=id",
350
+ headers=HEADERS
351
+ )
352
+ if res.status_code == 200:
353
+ count = len(res.json())
354
+ return f" Connected to Supabase. Users count: {count}"
355
+ else:
356
+ return f" Failed to fetch users: {res.text}"
357
  except Exception as e:
358
  return f" DB Error: {e}"
359