Add
Browse files
app.py
CHANGED
|
@@ -13,6 +13,7 @@ import json
|
|
| 13 |
import os
|
| 14 |
import pandas as pd
|
| 15 |
import shutil
|
|
|
|
| 16 |
# At the top with imports
|
| 17 |
from werkzeug.utils import secure_filename
|
| 18 |
|
|
@@ -57,6 +58,130 @@ def allowed_file(filename):
|
|
| 57 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 58 |
|
| 59 |
# Add this endpoint (before /parse)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
@app.route("/debug-permissions", methods=["GET"])
|
| 61 |
def debug_permissions():
|
| 62 |
try:
|
|
@@ -133,10 +258,37 @@ def upload_candidate_list():
|
|
| 133 |
return jsonify({"error": "No file selected"}), 400
|
| 134 |
|
| 135 |
if file and file.filename.endswith('.csv'):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
# Use /tmp directory which should be writable
|
| 137 |
filepath = '/tmp/test.csv'
|
| 138 |
-
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
|
| 141 |
# Validate CSV format
|
| 142 |
try:
|
|
@@ -149,17 +301,19 @@ def upload_candidate_list():
|
|
| 149 |
"found_columns": list(df.columns)
|
| 150 |
}), 400
|
| 151 |
|
| 152 |
-
#
|
| 153 |
try:
|
| 154 |
shutil.copy(filepath, './test.csv')
|
| 155 |
logging.info("Also copied to ./test.csv")
|
| 156 |
except Exception as copy_error:
|
| 157 |
-
logging.warning(f"Could not copy to ./test.csv: {copy_error}")
|
| 158 |
|
| 159 |
logging.info(f"Successfully validated CSV with {len(df)} candidates")
|
| 160 |
return jsonify({
|
| 161 |
"output": f"Successfully uploaded candidate list with {len(df)} candidates",
|
| 162 |
-
"candidates": len(df)
|
|
|
|
|
|
|
| 163 |
})
|
| 164 |
|
| 165 |
except Exception as e:
|
|
@@ -436,6 +590,13 @@ def email():
|
|
| 436 |
|
| 437 |
# Check for CSV file in multiple locations
|
| 438 |
csv_paths = ["/tmp/test.csv", "./test.csv"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 439 |
csv_path = None
|
| 440 |
|
| 441 |
for path in csv_paths:
|
|
|
|
| 13 |
import os
|
| 14 |
import pandas as pd
|
| 15 |
import shutil
|
| 16 |
+
import tempfile
|
| 17 |
# At the top with imports
|
| 18 |
from werkzeug.utils import secure_filename
|
| 19 |
|
|
|
|
| 58 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 59 |
|
| 60 |
# Add this endpoint (before /parse)
|
| 61 |
+
def cleanup_old_csv_files():
|
| 62 |
+
"""Helper function to clean up old test.csv files"""
|
| 63 |
+
csv_locations = ['/tmp/test.csv', './test.csv']
|
| 64 |
+
temp_dir = tempfile.gettempdir()
|
| 65 |
+
temp_csv_path = os.path.join(temp_dir, 'test.csv')
|
| 66 |
+
if temp_csv_path not in csv_locations:
|
| 67 |
+
csv_locations.append(temp_csv_path)
|
| 68 |
+
|
| 69 |
+
deleted_files = []
|
| 70 |
+
for csv_path in csv_locations:
|
| 71 |
+
try:
|
| 72 |
+
if os.path.exists(csv_path):
|
| 73 |
+
os.remove(csv_path)
|
| 74 |
+
deleted_files.append(csv_path)
|
| 75 |
+
logging.info(f"Deleted old CSV file: {csv_path}")
|
| 76 |
+
except Exception as e:
|
| 77 |
+
logging.warning(f"Could not delete {csv_path}: {e}")
|
| 78 |
+
|
| 79 |
+
return deleted_files
|
| 80 |
+
|
| 81 |
+
@app.route("/cleanup-csv", methods=["POST"])
|
| 82 |
+
def cleanup_csv():
|
| 83 |
+
"""Endpoint to manually clean up old CSV files"""
|
| 84 |
+
try:
|
| 85 |
+
deleted_files = cleanup_old_csv_files()
|
| 86 |
+
return jsonify({
|
| 87 |
+
"output": "CSV cleanup completed",
|
| 88 |
+
"deleted_files": deleted_files
|
| 89 |
+
})
|
| 90 |
+
except Exception as e:
|
| 91 |
+
logging.error(f"CSV cleanup error: {str(e)}")
|
| 92 |
+
return jsonify({"error": str(e)}), 500
|
| 93 |
+
|
| 94 |
+
@app.route("/check-csv", methods=["GET"])
|
| 95 |
+
def check_csv():
|
| 96 |
+
"""Check what CSV files currently exist"""
|
| 97 |
+
try:
|
| 98 |
+
csv_locations = ['/tmp/test.csv', './test.csv']
|
| 99 |
+
temp_dir = tempfile.gettempdir()
|
| 100 |
+
temp_csv_path = os.path.join(temp_dir, 'test.csv')
|
| 101 |
+
if temp_csv_path not in csv_locations:
|
| 102 |
+
csv_locations.append(temp_csv_path)
|
| 103 |
+
|
| 104 |
+
existing_files = {}
|
| 105 |
+
for csv_path in csv_locations:
|
| 106 |
+
if os.path.exists(csv_path):
|
| 107 |
+
try:
|
| 108 |
+
# Get file info
|
| 109 |
+
stat = os.stat(csv_path)
|
| 110 |
+
df = pd.read_csv(csv_path)
|
| 111 |
+
existing_files[csv_path] = {
|
| 112 |
+
"exists": True,
|
| 113 |
+
"size": stat.st_size,
|
| 114 |
+
"modified": stat.st_mtime,
|
| 115 |
+
"candidates": len(df),
|
| 116 |
+
"columns": list(df.columns)
|
| 117 |
+
}
|
| 118 |
+
except Exception as e:
|
| 119 |
+
existing_files[csv_path] = {
|
| 120 |
+
"exists": True,
|
| 121 |
+
"error": str(e)
|
| 122 |
+
}
|
| 123 |
+
else:
|
| 124 |
+
existing_files[csv_path] = {"exists": False}
|
| 125 |
+
|
| 126 |
+
return jsonify({
|
| 127 |
+
"csv_files": existing_files,
|
| 128 |
+
"temp_dir": tempfile.gettempdir()
|
| 129 |
+
})
|
| 130 |
+
|
| 131 |
+
except Exception as e:
|
| 132 |
+
logging.error(f"Check CSV error: {str(e)}")
|
| 133 |
+
return jsonify({"error": str(e)}), 500
|
| 134 |
+
|
| 135 |
+
@app.route("/test-file-save", methods=["POST"])
|
| 136 |
+
def test_file_save():
|
| 137 |
+
try:
|
| 138 |
+
# Test saving a simple file to different locations
|
| 139 |
+
test_content = "Name,Email\nJohn Doe,john@example.com\nJane Smith,jane@example.com"
|
| 140 |
+
|
| 141 |
+
results = {}
|
| 142 |
+
|
| 143 |
+
# Test /tmp
|
| 144 |
+
try:
|
| 145 |
+
with open('/tmp/test.csv', 'w') as f:
|
| 146 |
+
f.write(test_content)
|
| 147 |
+
results['/tmp/test.csv'] = 'SUCCESS'
|
| 148 |
+
logging.info("Successfully wrote to /tmp/test.csv")
|
| 149 |
+
except Exception as e:
|
| 150 |
+
results['/tmp/test.csv'] = f'FAILED: {str(e)}'
|
| 151 |
+
logging.error(f"Failed to write to /tmp/test.csv: {e}")
|
| 152 |
+
|
| 153 |
+
# Test current directory
|
| 154 |
+
try:
|
| 155 |
+
with open('./test.csv', 'w') as f:
|
| 156 |
+
f.write(test_content)
|
| 157 |
+
results['./test.csv'] = 'SUCCESS'
|
| 158 |
+
logging.info("Successfully wrote to ./test.csv")
|
| 159 |
+
except Exception as e:
|
| 160 |
+
results['./test.csv'] = f'FAILED: {str(e)}'
|
| 161 |
+
logging.error(f"Failed to write to ./test.csv: {e}")
|
| 162 |
+
|
| 163 |
+
# Test system temp
|
| 164 |
+
try:
|
| 165 |
+
temp_dir = tempfile.gettempdir()
|
| 166 |
+
temp_path = os.path.join(temp_dir, 'test.csv')
|
| 167 |
+
with open(temp_path, 'w') as f:
|
| 168 |
+
f.write(test_content)
|
| 169 |
+
results[temp_path] = 'SUCCESS'
|
| 170 |
+
logging.info(f"Successfully wrote to {temp_path}")
|
| 171 |
+
except Exception as e:
|
| 172 |
+
results[temp_path] = f'FAILED: {str(e)}'
|
| 173 |
+
logging.error(f"Failed to write to {temp_path}: {e}")
|
| 174 |
+
|
| 175 |
+
return jsonify({
|
| 176 |
+
"test_results": results,
|
| 177 |
+
"temp_dir": tempfile.gettempdir(),
|
| 178 |
+
"current_dir": os.getcwd()
|
| 179 |
+
})
|
| 180 |
+
|
| 181 |
+
except Exception as e:
|
| 182 |
+
logging.error(f"Test file save error: {str(e)}")
|
| 183 |
+
return jsonify({"error": str(e)}), 500
|
| 184 |
+
|
| 185 |
@app.route("/debug-permissions", methods=["GET"])
|
| 186 |
def debug_permissions():
|
| 187 |
try:
|
|
|
|
| 258 |
return jsonify({"error": "No file selected"}), 400
|
| 259 |
|
| 260 |
if file and file.filename.endswith('.csv'):
|
| 261 |
+
# Delete any existing test.csv files first
|
| 262 |
+
csv_locations = ['/tmp/test.csv', './test.csv']
|
| 263 |
+
temp_dir = tempfile.gettempdir()
|
| 264 |
+
temp_csv_path = os.path.join(temp_dir, 'test.csv')
|
| 265 |
+
if temp_csv_path not in csv_locations:
|
| 266 |
+
csv_locations.append(temp_csv_path)
|
| 267 |
+
|
| 268 |
+
for old_csv in csv_locations:
|
| 269 |
+
try:
|
| 270 |
+
if os.path.exists(old_csv):
|
| 271 |
+
os.remove(old_csv)
|
| 272 |
+
logging.info(f"Deleted existing CSV file: {old_csv}")
|
| 273 |
+
except Exception as delete_error:
|
| 274 |
+
logging.warning(f"Could not delete {old_csv}: {delete_error}")
|
| 275 |
+
|
| 276 |
# Use /tmp directory which should be writable
|
| 277 |
filepath = '/tmp/test.csv'
|
| 278 |
+
try:
|
| 279 |
+
file.save(filepath)
|
| 280 |
+
logging.info(f"Successfully saved new CSV file to: {filepath}")
|
| 281 |
+
except Exception as save_error:
|
| 282 |
+
logging.error(f"Failed to save to /tmp: {save_error}")
|
| 283 |
+
# Try alternative temp directory
|
| 284 |
+
temp_dir = tempfile.gettempdir()
|
| 285 |
+
filepath = os.path.join(temp_dir, 'test.csv')
|
| 286 |
+
try:
|
| 287 |
+
file.save(filepath)
|
| 288 |
+
logging.info(f"Successfully saved CSV file to alternative temp: {filepath}")
|
| 289 |
+
except Exception as alt_error:
|
| 290 |
+
logging.error(f"Failed to save to alternative temp: {alt_error}")
|
| 291 |
+
return jsonify({"error": f"Cannot save file to any writable location: {alt_error}"}), 500
|
| 292 |
|
| 293 |
# Validate CSV format
|
| 294 |
try:
|
|
|
|
| 301 |
"found_columns": list(df.columns)
|
| 302 |
}), 400
|
| 303 |
|
| 304 |
+
# Try to copy to the current directory for backward compatibility (optional)
|
| 305 |
try:
|
| 306 |
shutil.copy(filepath, './test.csv')
|
| 307 |
logging.info("Also copied to ./test.csv")
|
| 308 |
except Exception as copy_error:
|
| 309 |
+
logging.warning(f"Could not copy to ./test.csv (this is OK): {copy_error}")
|
| 310 |
|
| 311 |
logging.info(f"Successfully validated CSV with {len(df)} candidates")
|
| 312 |
return jsonify({
|
| 313 |
"output": f"Successfully uploaded candidate list with {len(df)} candidates",
|
| 314 |
+
"candidates": len(df),
|
| 315 |
+
"filepath": filepath,
|
| 316 |
+
"replaced_existing": True
|
| 317 |
})
|
| 318 |
|
| 319 |
except Exception as e:
|
|
|
|
| 590 |
|
| 591 |
# Check for CSV file in multiple locations
|
| 592 |
csv_paths = ["/tmp/test.csv", "./test.csv"]
|
| 593 |
+
|
| 594 |
+
# Also check system temp directory
|
| 595 |
+
temp_dir = tempfile.gettempdir()
|
| 596 |
+
temp_csv_path = os.path.join(temp_dir, 'test.csv')
|
| 597 |
+
if temp_csv_path not in csv_paths:
|
| 598 |
+
csv_paths.insert(1, temp_csv_path)
|
| 599 |
+
|
| 600 |
csv_path = None
|
| 601 |
|
| 602 |
for path in csv_paths:
|