Testys commited on
Commit
e0ac5b2
·
1 Parent(s): b7ed26f

WIP: Fixing bug

Browse files
Files changed (2) hide show
  1. src/database.py +63 -69
  2. src/models.py +6 -0
src/database.py CHANGED
@@ -1,99 +1,93 @@
 
 
 
 
1
  import sqlalchemy
2
- import os
3
- from dotenv import load_dotenv
4
  from datetime import datetime
5
 
 
 
 
6
  # Import Enums, Base, and specific ORM models needed for initialization
7
  from src.models import (
8
- UserRole, ClearanceDepartment, ClearanceStatusEnum, Base, TargetUserType,
9
- Student as StudentORM, # Alias to avoid confusion if Student Pydantic model is also imported
10
- ClearanceStatus as ClearanceStatusORM, # Alias for ORM model
11
- User as UserORM,
12
- Device as DeviceORM
13
  )
14
- from sqlalchemy.orm import Session as SQLAlchemySessionType
15
-
16
- # Load environment variables from a .env file
17
- load_dotenv()
18
 
19
- # Database setup
20
- DATABASE_URL = os.getenv("POSTGRES_URI") or os.getenv("DATABASE_URL")
 
 
 
 
21
 
22
- # Check if DATABASE_URL is set
23
- if not DATABASE_URL:
24
- raise ValueError("DATABASE_URL environment variable not set!")
25
 
26
- # SQLAlchemy engine
27
- engine = sqlalchemy.create_engine(DATABASE_URL)
 
 
 
 
 
 
 
 
28
 
29
- metadata = Base.metadata
30
 
31
- def create_db_tables():
32
- """Creates database tables based on SQLAlchemy ORM metadata."""
 
 
 
33
  try:
34
  print("Attempting to create database tables (if they don't exist)...")
35
- metadata.create_all(bind=engine) # Use Base.metadata from models.py
36
- print("Database tables creation attempt finished.")
37
  except Exception as e:
38
- print(f"Error during database table creation: {e}")
39
- print("Please ensure your database is accessible and the connection string is correct.")
 
 
40
 
41
-
42
- # Initialize default clearance statuses for new students (Synchronous ORM version)
43
- def initialize_student_clearance_statuses_orm(db: SQLAlchemySessionType, student_id_str: str):
44
  """
45
- Creates default clearance status entries for all departments for a new student.
46
- Uses SQLAlchemy ORM session.
 
47
  """
48
- created_rows_info = []
49
  student = db.query(StudentORM).filter(StudentORM.student_id == student_id_str).first()
50
  if not student:
51
- print(f"Warning: Student {student_id_str} not found when trying to initialize clearance statuses.")
52
  return
53
 
54
- for dept_enum_member in ClearanceDepartment: # Iterate through centralized Enum
55
- # Check if status already exists for this student and department
56
- existing_status = db.query(ClearanceStatusORM).filter(
57
  ClearanceStatusORM.student_id == student_id_str,
58
- ClearanceStatusORM.department == dept_enum_member
59
  ).first()
60
 
61
- if not existing_status:
 
62
  new_status = ClearanceStatusORM(
63
  student_id=student_id_str,
64
- department=dept_enum_member,
65
- status=ClearanceStatusEnum.NOT_COMPLETED,
66
- created_at=datetime.utcnow(),
67
- updated_at=datetime.utcnow()
68
  )
69
  db.add(new_status)
70
- created_rows_info.append({"department": dept_enum_member.value, "status": "initialized"})
71
- else:
72
- created_rows_info.append({"department": dept_enum_member.value, "status": "already_exists"})
73
 
74
- if created_rows_info:
75
- try:
76
- db.commit()
77
- print(f"Committed clearance statuses for student {student_id_str}: {created_rows_info}")
78
- except Exception as e:
79
- db.rollback()
80
- print(f"Error committing clearance statuses for student {student_id_str}: {e}")
81
- raise
82
- else:
83
- print(f"No new clearance statuses to initialize or commit for student {student_id_str}.")
84
-
85
-
86
- from sqlalchemy.orm import sessionmaker
87
-
88
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
89
-
90
- def get_db():
91
- """
92
- FastAPI dependency to get a SQLAlchemy database session.
93
- Ensures the session is closed after the request.
94
- """
95
- db = SessionLocal()
96
  try:
97
- yield db
98
- finally:
99
- db.close()
 
 
 
1
+ """
2
+ This module handles database connection, session management, table creation,
3
+ and initial data seeding.
4
+ """
5
  import sqlalchemy
6
+ from sqlalchemy.orm import sessionmaker, Session as SQLAlchemySessionType
 
7
  from datetime import datetime
8
 
9
+ # Import the centralized settings object
10
+ from src.config import settings
11
+
12
  # Import Enums, Base, and specific ORM models needed for initialization
13
  from src.models import (
14
+ Base,
15
+ ClearanceDepartment,
16
+ ClearanceStatusEnum,
17
+ Student as StudentORM,
18
+ ClearanceStatus as ClearanceStatusORM
19
  )
 
 
 
 
20
 
21
+ # --- Database Engine Setup ---
22
+ # Create the SQLAlchemy engine using the URI from our secure settings.
23
+ engine = sqlalchemy.create_engine(
24
+ settings.POSTGRES_URI,
25
+ pool_pre_ping=True # Helps prevent errors from stale connections
26
+ )
27
 
28
+ # --- Session Management ---
29
+ # Create a configured "Session" class. This is our session factory.
30
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
31
 
32
+ def get_db():
33
+ """
34
+ FastAPI dependency that creates and yields a new database session
35
+ for each request, and ensures it's closed afterward.
36
+ """
37
+ db = SessionLocal()
38
+ try:
39
+ yield db
40
+ finally:
41
+ db.close()
42
 
43
+ # --- Database Initialization Functions ---
44
 
45
+ def create_db_and_tables():
46
+ """
47
+ Creates all database tables defined in `src/models.py` if they do not exist.
48
+ This function should be called once on application startup.
49
+ """
50
  try:
51
  print("Attempting to create database tables (if they don't exist)...")
52
+ Base.metadata.create_all(bind=engine)
53
+ print("Database tables are ready.")
54
  except Exception as e:
55
+ print(f"FATAL: Error during database table creation: {e}")
56
+ print("Please ensure your database is accessible and the POSTGRES_URI is correct.")
57
+ # In a real production app, you might want to exit here if the DB is critical
58
+ raise
59
 
60
+ def initialize_student_clearance_statuses(db: SQLAlchemySessionType, student_id_str: str):
 
 
61
  """
62
+ Creates default 'NOT_COMPLETED' clearance status entries for all required
63
+ departments for a newly created student. This ensures every student's
64
+ clearance record is complete from the start.
65
  """
 
66
  student = db.query(StudentORM).filter(StudentORM.student_id == student_id_str).first()
67
  if not student:
68
+ print(f"Warning: Student '{student_id_str}' not found when trying to initialize clearance statuses.")
69
  return
70
 
71
+ for dept in ClearanceDepartment:
72
+ # Check if a status for this department already exists
73
+ exists = db.query(ClearanceStatusORM).filter(
74
  ClearanceStatusORM.student_id == student_id_str,
75
+ ClearanceStatusORM.department == dept
76
  ).first()
77
 
78
+ if not exists:
79
+ # If it doesn't exist, create the default record
80
  new_status = ClearanceStatusORM(
81
  student_id=student_id_str,
82
+ department=dept,
83
+ status=ClearanceStatusEnum.NOT_COMPLETED
 
 
84
  )
85
  db.add(new_status)
 
 
 
86
 
87
+ # Commit all the new statuses at once
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  try:
89
+ db.commit()
90
+ except Exception as e:
91
+ print(f"Error committing initial clearance statuses for student {student_id_str}: {e}")
92
+ db.rollback()
93
+ raise
src/models.py CHANGED
@@ -120,6 +120,12 @@ class ClearanceStatusEnum(str, Enum):
120
  COMPLETED = "COMPLETED"
121
  REJECTED = "REJECTED"
122
 
 
 
 
 
 
 
123
  class OverallClearanceStatusEnum(str, Enum):
124
  PENDING = "PENDING"
125
  COMPLETED = "COMPLETED"
 
120
  COMPLETED = "COMPLETED"
121
  REJECTED = "REJECTED"
122
 
123
+ class ClearanceDepartment(str, Enum):
124
+ DEPARTMENT = "DEPARTMENT"
125
+ BURSARY = "BURSARY"
126
+ LIBRARY = "LIBRARY"
127
+ ALUMNI = "ALUMNI"
128
+
129
  class OverallClearanceStatusEnum(str, Enum):
130
  PENDING = "PENDING"
131
  COMPLETED = "COMPLETED"