1
1
"""
2
2
Flask Application for Resume Management
3
3
"""
4
-
5
4
import os
6
5
import logging
6
+
7
+ from spellchecker import SpellChecker
8
+ from flask_cors import CORS
9
+
7
10
from werkzeug .utils import secure_filename
8
11
from flask import Flask , jsonify , request , send_from_directory
9
12
from models import Experience , Education , Skill , UserInformation
10
13
from helpers import validate_fields , validate_phone_number , load_data , save_data , generate_id
11
- from spellchecker import SpellChecker
12
- from flask_cors import CORS
14
+
13
15
14
16
spell = SpellChecker ()
15
17
@@ -58,8 +60,10 @@ def reset_data():
58
60
UserInformation (
"Joe Smith" ,
"[email protected] " ,
"+11234567890" ),
59
61
]
60
62
63
+
61
64
#reset_data()
62
65
66
+
63
67
def allowed_file (filename ):
64
68
"""
65
69
Check if the uploaded file has an allowed extension.
@@ -69,6 +73,7 @@ def allowed_file(filename):
69
73
"""
70
74
return "." in filename and filename .rsplit ("." , 1 )[1 ].lower () in ALLOWED_EXTENSIONS
71
75
76
+
72
77
def handle_missing_invalid_fields (request_body , required_fields ):
73
78
"""
74
79
Check for missing and invalid fields in the request body.
@@ -85,20 +90,23 @@ def handle_missing_invalid_fields(request_body, required_fields):
85
90
]
86
91
return missing_fields , invalid_fields
87
92
93
+
88
94
@app .route ("/" , strict_slashes = False )
89
95
def home ():
90
96
"""
91
97
Returns a welcome message for the app
92
98
"""
93
99
return "Welcome to MLH 24.FAL.A.2 Orientation API Project!!"
94
100
101
+
95
102
@app .route ("/test" )
96
103
def hello_world ():
97
104
"""
98
105
Returns a JSON test message
99
106
"""
100
107
return jsonify ({"message" : "Hello, World!" })
101
108
109
+
102
110
@app .route ("/resume/experience" , methods = ["GET" , "POST" ])
103
111
def experience ():
104
112
"""
@@ -108,19 +116,36 @@ def experience():
108
116
return jsonify ([exp .__dict__ for exp in data ["experience" ]]), 200
109
117
110
118
if request .method == "POST" :
111
- request_body = request .form if request .content_type == "multipart/form-data" else request .get_json ()
119
+ request_body = (
120
+ request .form
121
+ if request .content_type == "multipart/form-data"
122
+ else request .get_json ()
123
+ )
112
124
if not request_body :
113
125
return jsonify ({"error" : "Request must be JSON or include form data" }), 400
114
126
115
- required_fields = {"title" : str , "company" : str , "start_date" : str , "end_date" : str , "description" : str }
116
- missing_fields , invalid_fields = handle_missing_invalid_fields (request_body , required_fields )
127
+ required_fields = {
128
+ "title" : str ,
129
+ "company" : str ,
130
+ "start_date" : str ,
131
+ "end_date" : str ,
132
+ "description" : str ,
133
+ }
134
+ missing_fields , invalid_fields = handle_missing_invalid_fields (
135
+ request_body , required_fields
136
+ )
117
137
118
138
if missing_fields or invalid_fields :
119
- return jsonify ({
120
- "error" : "Validation failed" ,
121
- "missing_fields" : missing_fields ,
122
- "invalid_fields" : invalid_fields
123
- }), 400
139
+ return (
140
+ jsonify (
141
+ {
142
+ "error" : "Validation failed" ,
143
+ "missing_fields" : missing_fields ,
144
+ "invalid_fields" : invalid_fields ,
145
+ }
146
+ ),
147
+ 400 ,
148
+ )
124
149
125
150
# Handle logo file
126
151
logo_filename = DEFAULT_LOGO
@@ -130,7 +155,7 @@ def experience():
130
155
filename = secure_filename (logo_file .filename )
131
156
logo_file .save (os .path .join (app .config ["UPLOAD_FOLDER" ], filename ))
132
157
logo_filename = filename
133
-
158
+
134
159
# Create new experience
135
160
new_id = generate_id (data , 'experience' )
136
161
@@ -149,6 +174,9 @@ def experience():
149
174
new_experience_index = len (data ["experience" ]) - 1
150
175
return jsonify ({"message" : "New experience created" , "id" : new_experience_index }), 201
151
176
177
+ return 400
178
+
179
+
152
180
@app .route ("/resume/experience/<int:index>" , methods = ["DELETE" ])
153
181
def delete_experience (index ):
154
182
"""
@@ -173,16 +201,24 @@ def education():
173
201
if not request_body :
174
202
return jsonify ({"error" : "Request must be JSON" }), 400
175
203
176
- required_fields = {"course" : str , "school" : str , "start_date" : str , "end_date" : str , "grade" : str }
177
- missing_fields , invalid_fields = handle_missing_invalid_fields (request_body , required_fields )
204
+ required_fields = {
205
+ "course" : str ,
206
+ "school" : str ,
207
+ "start_date" : str ,
208
+ "end_date" : str ,
209
+ "grade" : str ,
210
+ }
211
+ missing_fields , invalid_fields = handle_missing_invalid_fields (
212
+ request_body , required_fields
213
+ )
178
214
179
215
if missing_fields or invalid_fields :
180
216
return jsonify ({
181
217
"error" : "Validation failed" ,
182
218
"missing_fields" : missing_fields ,
183
219
"invalid_fields" : invalid_fields
184
220
}), 400
185
-
221
+
186
222
new_id = generate_id (data , 'education' )
187
223
188
224
# Create new education entry
@@ -200,6 +236,8 @@ def education():
200
236
new_education_index = new_id - 1
201
237
return jsonify ({"message" : "New education created" , "id" : new_education_index }), 201
202
238
239
+ return 400
240
+
203
241
204
242
@app .route ("/resume/experience/<int:index>" , methods = ["GET" ])
205
243
def experience_by_index (index ):
@@ -220,6 +258,7 @@ def education_by_index(index):
220
258
return jsonify (data ["education" ][index ].__dict__ ), 200
221
259
return jsonify ({"error" : "Education not found" }), 404
222
260
261
+
223
262
@app .route ("/resume/education/<int:index>" , methods = ["DELETE" ])
224
263
def delete_education (index ):
225
264
"""
@@ -240,19 +279,30 @@ def skill():
240
279
return jsonify ([sk .__dict__ for sk in data ["skill" ]]), 200
241
280
242
281
if request .method == "POST" :
243
- request_body = request .form if request .content_type == "multipart/form-data" else request .get_json ()
282
+ request_body = (
283
+ request .form
284
+ if request .content_type == "multipart/form-data"
285
+ else request .get_json ()
286
+ )
244
287
if not request_body :
245
288
return jsonify ({"error" : "Request must be JSON or include form data" }), 400
246
289
247
290
required_fields = {"name" : str , "proficiency" : str }
248
- missing_fields , invalid_fields = handle_missing_invalid_fields (request_body , required_fields )
291
+ missing_fields , invalid_fields = handle_missing_invalid_fields (
292
+ request_body , required_fields
293
+ )
249
294
250
295
if missing_fields or invalid_fields :
251
- return jsonify ({
252
- "error" : "Validation failed" ,
253
- "missing_fields" : missing_fields ,
254
- "invalid_fields" : invalid_fields
255
- }), 400
296
+ return (
297
+ jsonify (
298
+ {
299
+ "error" : "Validation failed" ,
300
+ "missing_fields" : missing_fields ,
301
+ "invalid_fields" : invalid_fields ,
302
+ }
303
+ ),
304
+ 400 ,
305
+ )
256
306
257
307
# Handle logo file
258
308
logo_filename = DEFAULT_LOGO
@@ -264,11 +314,16 @@ def skill():
264
314
logo_filename = filename
265
315
266
316
# Create new skill
267
- new_skill = Skill (request_body ["name" ], request_body ["proficiency" ], logo_filename )
317
+ new_skill = Skill (
318
+ request_body ["name" ], request_body ["proficiency" ], logo_filename
319
+ )
268
320
data ["skill" ].append (new_skill )
321
+
269
322
save_data ('data/data.json' , data )
270
323
return jsonify ({"message" : "New skill created" , "id" : len (data ["skill" ]) - 1 }), 201
271
324
325
+ return 400
326
+
272
327
273
328
@app .route ("/resume/user_information" , methods = ["GET" , "POST" , "PUT" ])
274
329
def user_information ():
@@ -290,6 +345,9 @@ def user_information():
290
345
data ["user_information" ] = request .json
291
346
return jsonify (data ["user_information" ]), 201
292
347
348
+ return 400
349
+
350
+
293
351
@app .route ("/resume/skill/<int:index>" , methods = ["DELETE" ])
294
352
def delete_skill (index ):
295
353
"""
@@ -303,10 +361,12 @@ def delete_skill(index):
303
361
return jsonify ({"error" : "Skill not found" }), 404
304
362
305
363
306
-
307
-
308
364
@app .route ("/resume/spellcheck" , methods = ["POST" ])
309
365
def spellcheck ():
366
+ """
367
+ Spellcheck the resume.
368
+ (TODO add more detailed info here)
369
+ """
310
370
request_body = request .get_json ()
311
371
if not request_body :
312
372
return jsonify ({"error" : "Request must be JSON" }), 400
@@ -317,34 +377,55 @@ def spellcheck():
317
377
title = exp .get ("title" , "" )
318
378
description = exp .get ("description" , "" )
319
379
if title :
320
- results .append ({
321
- "before" : title ,
322
- "after" : list (spell .candidates (title )) if spell .candidates (title ) else []
323
- })
380
+ results .append (
381
+ {
382
+ "before" : title ,
383
+ "after" : (
384
+ list (spell .candidates (title )) if spell .candidates (title ) else []
385
+ ),
386
+ }
387
+ )
324
388
if description :
325
- results .append ({
326
- "before" : description ,
327
- "after" : list (spell .candidates (description )) if spell .candidates (description ) else []
328
- })
389
+ results .append (
390
+ {
391
+ "before" : description ,
392
+ "after" : (
393
+ list (spell .candidates (description ))
394
+ if spell .candidates (description )
395
+ else []
396
+ ),
397
+ }
398
+ )
329
399
330
400
for edu in request_body .get ("education" , []):
331
401
course = edu .get ("course" , "" )
332
402
if course :
333
- results .append ({
334
- "before" : course ,
335
- "after" : list (spell .candidates (course )) if spell .candidates (course ) else []
336
- })
403
+ results .append (
404
+ {
405
+ "before" : course ,
406
+ "after" : (
407
+ list (spell .candidates (course ))
408
+ if spell .candidates (course )
409
+ else []
410
+ ),
411
+ }
412
+ )
337
413
338
414
for sk in request_body .get ("skill" , []):
339
415
name = sk .get ("name" , "" )
340
416
if name :
341
- results .append ({
342
- "before" : name ,
343
- "after" : list (spell .candidates (name )) if spell .candidates (name ) else []
344
- })
417
+ results .append (
418
+ {
419
+ "before" : name ,
420
+ "after" : (
421
+ list (spell .candidates (name )) if spell .candidates (name ) else []
422
+ ),
423
+ }
424
+ )
345
425
346
426
return jsonify (results ), 200
347
427
428
+
348
429
@app .route ("/custom-section" , methods = ["POST" ])
349
430
def add_custom_section ():
350
431
"""
@@ -368,18 +449,21 @@ def add_custom_section():
368
449
logging .info ("New custom section added: %s" , title )
369
450
return jsonify ({"message" : "Custom section added" , "id" : section_id }), 201
370
451
452
+
371
453
@app .route ("/custom-sections" , methods = ["GET" ])
372
454
def get_custom_sections ():
373
455
"""
374
456
Retrieve all custom sections added by the user.
375
457
"""
376
458
return jsonify (data ["custom_sections" ]), 200
377
459
460
+
378
461
if __name__ == "__main__" :
379
462
if not os .path .exists (UPLOAD_FOLDER ):
380
463
os .makedirs (UPLOAD_FOLDER )
381
464
app .run (debug = True )
382
465
466
+
383
467
@app .route ("/uploads/<path:filename>" )
384
468
def uploaded_file (filename ):
385
469
"""
0 commit comments