blueprint-api / database.py
mohamedhuggig's picture
Update database.py
f71cc05 verified
import sys
import os
sys.stdout.reconfigure(encoding='utf-8')
from sqlalchemy import create_engine, Column, Integer, String, Text, DateTime, ForeignKey, JSON, Float, Boolean, Date
from sqlalchemy.orm import declarative_base, sessionmaker, relationship
from datetime import datetime
from passlib.context import CryptContext
import os
# ✅ التعديل هنا: استخدام SQLite افتراضياً للتشغيل المحلي
SQLALCHEMY_DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./blueprint.db")
# دعم كل من PostgreSQL و SQLite
if SQLALCHEMY_DATABASE_URL.startswith("postgresql"):
engine = create_engine(SQLALCHEMY_DATABASE_URL)
else:
# SQLite يحتاج connect_args
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto")
# ---------- نماذج المستخدمين والصلاحيات ----------
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True, nullable=False)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
full_name = Column(String)
role = Column(String, default="viewer") # admin, engineer, viewer
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
projects = relationship("ProjectUser", back_populates="user")
class ProjectUser(Base):
__tablename__ = "project_users"
id = Column(Integer, primary_key=True)
project_id = Column(Integer, ForeignKey("projects.id"))
user_id = Column(Integer, ForeignKey("users.id"))
permission = Column(String, default="read") # read, write, admin
user = relationship("User", back_populates="projects")
project = relationship("Project", back_populates="users")
# ---------- المشاريع ----------
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False, index=True)
location = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
analyses = relationship("Analysis", back_populates="project", cascade="all, delete-orphan")
site_reports = relationship("SiteReport", back_populates="project", cascade="all, delete-orphan")
boq_items = relationship("BOQItem", back_populates="project", cascade="all, delete-orphan")
files = relationship("UploadedFile", back_populates="project", cascade="all, delete-orphan")
defects = relationship("Defect", back_populates="project", cascade="all, delete-orphan")
users = relationship("ProjectUser", back_populates="project", cascade="all, delete-orphan")
site_visits = relationship("SiteVisit", back_populates="project", cascade="all, delete-orphan")
memory_entries = relationship("MemoryEntry", back_populates="project", cascade="all, delete-orphan")
workflows = relationship("Workflow", back_populates="project", cascade="all, delete-orphan")
tasks = relationship("Task", back_populates="project", cascade="all, delete-orphan") # NEW
# ---------- التحليلات ----------
class Analysis(Base):
__tablename__ = "analyses"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
task_type = Column(String)
input_text = Column(Text)
result_json = Column(JSON)
safety_status = Column(String, default="Pending")
created_at = Column(DateTime, default=datetime.utcnow, index=True)
project = relationship("Project", back_populates="analyses")
class SiteReport(Base):
__tablename__ = "site_reports"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"))
report_date = Column(DateTime, default=datetime.utcnow)
weather = Column(String)
workers_count = Column(Integer)
summary = Column(Text)
issues = Column(Text)
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", back_populates="site_reports")
# ---------- حصر الكميات ----------
class BOQItem(Base):
__tablename__ = "boq_items"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
description = Column(String)
unit = Column(String)
quantity = Column(Float)
unit_price = Column(Float)
total_price = Column(Float)
project = relationship("Project", back_populates="boq_items")
# ---------- الملفات المرفوعة ----------
class UploadedFile(Base):
__tablename__ = "uploaded_files"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
filename = Column(String)
file_type = Column(String)
file_path = Column(String)
analyzed = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", back_populates="files")
# ---------- العيوب ----------
class Defect(Base):
__tablename__ = "defects"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
description = Column(Text)
severity = Column(String) # High, Medium, Low
status = Column(String, default="Open") # Open, Resolved
image_id = Column(Integer, ForeignKey("uploaded_files.id"), nullable=True)
assigned_to = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", back_populates="defects")
assignee = relationship("User", foreign_keys=[assigned_to])
# ---------- إعدادات المشروع ----------
class ProjectSettings(Base):
__tablename__ = "project_settings"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), unique=True, index=True)
concrete_price = Column(Float, default=1000.0)
steel_price = Column(Float, default=35000.0)
preferred_ai_model = Column(String, default="gemini")
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", backref="settings", uselist=False)
# ---------- زيارات الموقع ----------
class SiteVisit(Base):
__tablename__ = "site_visits"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
visit_date = Column(DateTime, default=datetime.utcnow)
location_name = Column(String, nullable=True)
latitude = Column(Float, nullable=True)
longitude = Column(Float, nullable=True)
notes = Column(Text, nullable=True)
created_by = Column(Integer, ForeignKey("users.id"), nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", back_populates="site_visits")
creator = relationship("User", foreign_keys=[created_by])
images = relationship("SiteVisitImage", back_populates="site_visit", cascade="all, delete-orphan")
class SiteVisitImage(Base):
__tablename__ = "site_visit_images"
id = Column(Integer, primary_key=True, index=True)
site_visit_id = Column(Integer, ForeignKey("site_visits.id"), index=True)
image_path = Column(String)
caption = Column(String, nullable=True)
timestamp = Column(DateTime, nullable=True)
latitude = Column(Float, nullable=True)
longitude = Column(Float, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
site_visit = relationship("SiteVisit", back_populates="images")
# ---------- الذاكرة طويلة المدى ----------
class MemoryEntry(Base):
__tablename__ = "memory_entries"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
entry_type = Column(String) # decision, pattern, context, progress
title = Column(String)
content = Column(Text)
tags = Column(String) # مفصول بفواصل
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
project = relationship("Project", back_populates="memory_entries")
# ---------- سير العمل الآلي ----------
class Workflow(Base):
__tablename__ = "workflows"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
name = Column(String)
trigger_event = Column(String) # image_upload, defect_created, design_completed
action_type = Column(String) # notify, create_defect, update_boq, send_message
action_params = Column(JSON)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
project = relationship("Project", back_populates="workflows")
class WorkflowLog(Base):
__tablename__ = "workflow_logs"
id = Column(Integer, primary_key=True, index=True)
workflow_id = Column(Integer, ForeignKey("workflows.id"))
triggered_by = Column(String)
status = Column(String) # success, failed
result = Column(JSON)
created_at = Column(DateTime, default=datetime.utcnow)
workflow = relationship("Workflow")
# ---------- المهام (NEW) ----------
class Task(Base):
__tablename__ = "tasks"
id = Column(Integer, primary_key=True, index=True)
project_id = Column(Integer, ForeignKey("projects.id"), index=True)
description = Column(String, nullable=False)
assignee = Column(String, nullable=False)
due_date = Column(Date, nullable=False)
priority = Column(String, nullable=False) # منخفضة، متوسطة، عالية
status = Column(String, default="قيد الانتظار") # قيد الانتظار، جاري، منتهية
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
project = relationship("Project", back_populates="tasks")
# ---------- دالة تهيئة قاعدة البيانات ----------
def init_db():
Base.metadata.create_all(bind=engine)
# ---------- دوال مساعدة للمستخدمين ----------
def get_password_hash(password):
return pwd_context.hash(password)
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)