Spaces:
Sleeping
Sleeping
File size: 6,612 Bytes
04a16eb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
"""
Database models for NeuroSight authentication system
"""
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
import secrets
db = SQLAlchemy()
class User(UserMixin, db.Model):
"""User model for doctors and radiologists"""
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True, nullable=False, index=True)
password_hash = db.Column(db.String(255), nullable=True) # Nullable for OAuth users
full_name = db.Column(db.String(255), nullable=False)
role = db.Column(db.String(50), nullable=False) # 'doctor' or 'radiologist'
hospital = db.Column(db.String(255))
license_number = db.Column(db.String(100))
phone = db.Column(db.String(20))
is_verified = db.Column(db.Boolean, default=False)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
last_login = db.Column(db.DateTime)
# OAuth fields
google_id = db.Column(db.String(255), unique=True, index=True)
profile_photo_url = db.Column(db.String(500))
# Password reset fields
reset_token = db.Column(db.String(255))
reset_token_expiry = db.Column(db.DateTime)
# Doctor Details (for onboarding)
medical_registration_no = db.Column(db.String(100))
specialization = db.Column(db.String(100))
years_of_experience = db.Column(db.Integer)
clinic_timing = db.Column(db.String(255))
# Hospital Details (for onboarding)
hospital_id = db.Column(db.String(100))
hospital_address = db.Column(db.Text)
department = db.Column(db.String(100))
hospital_logo_url = db.Column(db.String(500))
hospital_phone = db.Column(db.String(20))
# Onboarding tracking
onboarding_completed = db.Column(db.Boolean, default=False)
# Email verification with OTP
email_verified = db.Column(db.Boolean, default=False)
otp_code = db.Column(db.String(6))
otp_expiry = db.Column(db.DateTime)
otp_attempts = db.Column(db.Integer, default=0)
# Relationships
analyses = db.relationship('AnalysisHistory', backref='user', lazy='dynamic', cascade='all, delete-orphan')
def set_password(self, password):
"""Hash and set password"""
self.password_hash = generate_password_hash(password)
def check_password(self, password):
"""Verify password against hash"""
if not self.password_hash:
return False
return check_password_hash(self.password_hash, password)
def generate_reset_token(self):
"""Generate a secure password reset token"""
self.reset_token = secrets.token_urlsafe(32)
return self.reset_token
def generate_otp(self):
"""Generate a 6-digit OTP for email verification"""
import random
from datetime import datetime, timedelta
self.otp_code = ''.join([str(random.randint(0, 9)) for _ in range(6)])
self.otp_expiry = datetime.utcnow() + timedelta(minutes=10) # OTP valid for 10 minutes
self.otp_attempts = 0
return self.otp_code
def verify_otp(self, otp):
"""Verify the OTP code"""
from datetime import datetime
# Check if OTP exists
if not self.otp_code:
return False, "No OTP generated"
# Check if OTP has expired
if datetime.utcnow() > self.otp_expiry:
return False, "OTP has expired"
# Check attempt limit (max 5 attempts)
if self.otp_attempts >= 5:
return False, "Too many failed attempts. Please request a new OTP"
# Verify OTP
if self.otp_code == otp:
self.email_verified = True
self.otp_code = None
self.otp_expiry = None
self.otp_attempts = 0
return True, "Email verified successfully"
else:
self.otp_attempts += 1
remaining = 5 - self.otp_attempts
return False, f"Invalid OTP. {remaining} attempts remaining"
def needs_onboarding(self):
"""Check if user needs to complete onboarding"""
return not self.onboarding_completed
def has_required_doctor_details(self):
"""Check if user has all required doctor details"""
return all([
self.full_name,
self.medical_registration_no,
self.specialization,
self.phone,
self.email,
self.years_of_experience is not None
])
def has_required_hospital_details(self):
"""Check if user has all required hospital details"""
return all([
self.hospital,
self.hospital_id,
self.department
])
def can_complete_onboarding(self):
"""Check if user can complete onboarding (all required fields filled)"""
return self.has_required_doctor_details() and self.has_required_hospital_details()
def __repr__(self):
return f'<User {self.email}>'
class AnalysisHistory(db.Model):
"""Analysis history for tracking patient scans"""
__tablename__ = 'analysis_history'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
# Patient information
patient_name = db.Column(db.String(255))
patient_id = db.Column(db.String(100))
patient_age = db.Column(db.Integer)
scan_date = db.Column(db.Date)
# Analysis results
disease_type = db.Column(db.String(50), nullable=False) # 'ms', 'alzheimer', 'dementia', 'stroke'
prediction = db.Column(db.String(255), nullable=False)
confidence = db.Column(db.Float)
# File paths
image_path = db.Column(db.String(500))
report_path = db.Column(db.String(500))
# Metadata
created_at = db.Column(db.DateTime, default=datetime.utcnow, index=True)
notes = db.Column(db.Text) # Doctor's notes
def __repr__(self):
return f'<Analysis {self.id} - {self.disease_type}>'
def init_db(app):
"""Initialize database"""
db.init_app(app)
with app.app_context():
db.create_all()
print("✓ Database tables created successfully")
|