Skip to content

Commit 7a0a234

Browse files
author
Uttam Singh
committed
Added forgot-password route and updated main.py
1 parent 0307aa0 commit 7a0a234

File tree

2 files changed

+168
-11
lines changed

2 files changed

+168
-11
lines changed

backend/app/main.py

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,50 @@
77
import os, shutil
88
from dotenv import load_dotenv
99

10-
# ⬇️ your database bits
10+
# ==============================
11+
# 1️⃣ Load environment variables
12+
# ==============================
1113
load_dotenv()
14+
1215
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./app.db")
1316
engine = create_engine(DATABASE_URL, pool_pre_ping=True)
1417
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
1518
Base = declarative_base()
1619

17-
# ⬇️ import models so SQLAlchemy knows about User
18-
from app import models
19-
# … define Task/AuditLog classes …
20+
21+
# ==============================
22+
# 2️⃣ Database models (Tasks, Audit Logs)
23+
# ==============================
24+
class Task(Base):
25+
__tablename__ = "tasks"
26+
id = Column(Integer, primary_key=True, index=True)
27+
title = Column(String(255), nullable=False)
28+
department = Column(String(100), nullable=True)
29+
assignee = Column(String(100), nullable=True)
30+
status = Column(String(50), nullable=False, default="Pending")
31+
due_date = Column(Date, nullable=True)
32+
priority = Column(String(20), nullable=True)
33+
remarks = Column(Text, nullable=True)
34+
attachment = Column(String(255), nullable=True)
35+
36+
37+
class AuditLog(Base):
38+
__tablename__ = "audit_logs"
39+
id = Column(Integer, primary_key=True)
40+
action = Column(String(50))
41+
detail = Column(Text)
42+
43+
44+
# ✅ Create all tables initially (will also be re-created by /create-db)
2045
Base.metadata.create_all(bind=engine)
2146

47+
48+
# ==============================
49+
# 3️⃣ FastAPI app setup
50+
# ==============================
2251
app = FastAPI(title="FAT-EIBL (Edme) – API")
2352

24-
# CORS
53+
# ✅ Enable CORS for frontend
2554
allow = os.getenv("ALLOW_ORIGINS", "*").split(",")
2655
app.add_middleware(
2756
CORSMiddleware,
@@ -31,18 +60,75 @@
3160
allow_headers=["*"],
3261
)
3362

34-
# at the bottom: include users router
35-
from app.routers import users
63+
64+
# ==============================
65+
# 4️⃣ Database dependency
66+
# ==============================
67+
def get_db():
68+
db = SessionLocal()
69+
try:
70+
yield db
71+
finally:
72+
db.close()
73+
74+
75+
# ==============================
76+
# 5️⃣ Import Routers (User + Forgot Password)
77+
# ==============================
78+
from app.routers import users, forgot_password
79+
3680
app.include_router(users.router, prefix="/users", tags=["Users"])
37-
# --- TEMPORARY: Create Database Tables on Render ---
81+
app.include_router(forgot_password.router, prefix="/users", tags=["Forgot Password"])
82+
83+
84+
# ==============================
85+
# 6️⃣ Health check
86+
# ==============================
87+
@app.get("/health")
88+
def health():
89+
return {"status": "ok", "message": "Backend is running"}
90+
91+
92+
# ==============================
93+
# 7️⃣ File Uploads (optional)
94+
# ==============================
95+
UPLOAD_DIR = os.path.join(os.getcwd(), "uploads")
96+
os.makedirs(UPLOAD_DIR, exist_ok=True)
97+
98+
99+
@app.post("/upload/{task_id}")
100+
async def upload_file(task_id: int, file: UploadFile = File(...), db: Session = Depends(get_db)):
101+
obj = db.get(Task, task_id)
102+
if not obj:
103+
raise HTTPException(status_code=404, detail="Task not found")
104+
105+
safe_name = f"task_{task_id}_" + os.path.basename(file.filename)
106+
dest = os.path.join(UPLOAD_DIR, safe_name)
107+
108+
with open(dest, "wb") as buffer:
109+
shutil.copyfileobj(file.file, buffer)
110+
111+
obj.attachment = safe_name
112+
db.add(AuditLog(action="upload", detail=f"Task ID {task_id} file {safe_name}"))
113+
db.commit()
114+
115+
return {"task_id": task_id, "filename": safe_name}
116+
117+
118+
# ==============================
119+
# 8️⃣ Emergency endpoint: Create database tables
120+
# ==============================
38121
from app.models.user import User
39-
from app.database import Base, engine
122+
from app.database import Base as DBBase, engine as DBEngine
123+
40124

41125
@app.get("/create-db")
42126
def create_database():
127+
"""
128+
🔧 Use this endpoint on Render once if tables fail to auto-create.
129+
"""
43130
try:
44-
Base.metadata.create_all(bind=engine)
131+
DBBase.metadata.create_all(bind=DBEngine)
45132
return {"ok": True, "message": "Database tables created successfully"}
46133
except Exception as e:
47134
return {"ok": False, "error": str(e)}
48-
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from fastapi import APIRouter, Form, HTTPException, Depends
2+
from sqlalchemy.orm import Session
3+
from app.database import get_db
4+
from app.models.user import User
5+
import random
6+
import smtplib
7+
from email.mime.text import MIMEText
8+
from email.mime.multipart import MIMEMultipart
9+
import os
10+
11+
router = APIRouter()
12+
13+
# ✅ Generate random 6-digit OTP
14+
def generate_otp():
15+
return str(random.randint(100000, 999999))
16+
17+
# ✅ Send email via company mail (SMTP)
18+
def send_otp_email(recipient_email: str, otp: str):
19+
sender_email = os.getenv("SMTP_SENDER_EMAIL", "[email protected]")
20+
sender_password = os.getenv("SMTP_PASSWORD", "your-app-password")
21+
smtp_server = os.getenv("SMTP_SERVER", "smtp.office365.com")
22+
smtp_port = int(os.getenv("SMTP_PORT", 587))
23+
24+
subject = "FAT-EIBL Password Reset OTP"
25+
body = f"""
26+
<html>
27+
<body>
28+
<p>Dear User,</p>
29+
<p>Your OTP for password reset is: <b>{otp}</b></p>
30+
<p>This OTP will expire in 10 minutes.</p>
31+
<p>Regards,<br>Finance Audit Tracker - Edme Insurance Brokers Ltd</p>
32+
</body>
33+
</html>
34+
"""
35+
36+
msg = MIMEMultipart()
37+
msg["From"] = sender_email
38+
msg["To"] = recipient_email
39+
msg["Subject"] = subject
40+
msg.attach(MIMEText(body, "html"))
41+
42+
try:
43+
with smtplib.SMTP(smtp_server, smtp_port) as server:
44+
server.starttls()
45+
server.login(sender_email, sender_password)
46+
server.send_message(msg)
47+
print(f"✅ OTP sent to {recipient_email}")
48+
except Exception as e:
49+
print(f"❌ Error sending OTP: {e}")
50+
raise HTTPException(status_code=500, detail="Failed to send OTP email")
51+
52+
# ✅ Store OTP temporarily (in memory)
53+
otp_storage = {}
54+
55+
@router.post("/forgot-password")
56+
def forgot_password(email: str = Form(...), db: Session = Depends(get_db)):
57+
# Check if user exists
58+
user = db.query(User).filter(User.email == email).first()
59+
if not user:
60+
raise HTTPException(status_code=404, detail="Email not registered")
61+
62+
# Generate OTP
63+
otp = generate_otp()
64+
65+
# Save OTP temporarily (could use Redis or DB for production)
66+
otp_storage[email] = otp
67+
68+
# Send email
69+
send_otp_email(email, otp)
70+
71+
return {"ok": True, "message": f"OTP sent to {email}. Please check your inbox."}

0 commit comments

Comments
 (0)