Skip to content

Commit 017c798

Browse files
orabeCopilot
andcommitted
Add status column to Certificate model and update related functionality
- Introduced 'status' column with default value 'valid' to the Certificate model. - Enhanced certificate verification response to include student and certificate timestamps. - Updated database schema to ensure the new 'status' column is added if missing. - Improved .env loading mechanism in view_database script for better environment variable management. Co-authored-by: Copilot <copilot@github.com>
1 parent 83d5701 commit 017c798

5 files changed

Lines changed: 57 additions & 3 deletions

File tree

backend/app/database.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ def ensure_certificate_schema(bind=None):
7171
missing_statements.append("ALTER TABLE certificates ADD COLUMN instruction_language VARCHAR")
7272
if "course_link" not in existing_columns:
7373
missing_statements.append("ALTER TABLE certificates ADD COLUMN course_link VARCHAR")
74+
if "status" not in existing_columns:
75+
# create status column with a sensible default so existing DBs don't fail on inserts
76+
# Use DEFAULT and NOT NULL in a single statement when supported by the DB.
77+
missing_statements.append("ALTER TABLE certificates ADD COLUMN status VARCHAR DEFAULT 'valid' NOT NULL")
7478

7579
if not missing_statements:
7680
return

backend/app/main.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def verify_certificate(certificate_id: str, db: Session = Depends(get_db)):
6565
"message": "Certificate not found"
6666
})
6767

68+
student = getattr(cert, "student", None)
69+
6870
return {
6971
"status": "valid",
7072
"certificate_id": cert.certificate_id,
@@ -76,6 +78,15 @@ def verify_certificate(certificate_id: str, db: Session = Depends(get_db)):
7678
"duration_hours": cert.duration_hours,
7779
"issuer": cert.issuer,
7880
"instructor": cert.instructor,
81+
"attendance_percentage": cert.attendance_percentage,
82+
"assignment_completion_percentage": cert.assignment_completion_percentage,
83+
"course_level": cert.course_level,
84+
"course_format": cert.course_format,
85+
"instruction_language": cert.instruction_language,
86+
"certificate_created_at": cert.created_at,
87+
"certificate_updated_at": cert.updated_at,
88+
"student_created_at": getattr(student, "created_at", None) if student else None,
89+
"student_updated_at": getattr(student, "updated_at", None) if student else None,
7990
"verified_at": datetime.utcnow().isoformat() + "Z",
8091
"verification_url": f"https://mathcodelab.de/verify/?id={cert.certificate_id}"
8192
}

backend/app/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Certificate(Base):
2525
course_format = Column(String, nullable=True)
2626
instruction_language = Column(String, nullable=True)
2727
course_link = Column(String, nullable=True)
28+
status = Column(String, default="valid", server_default="valid", nullable=False)
2829

2930
issuer = Column(String, default="MathCodeLab", nullable=False)
3031
instructor = Column(String, default="Mohammad Orabe", nullable=False)

backend/app/schemas.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ class CertificateVerificationResponse(BaseModel):
5555
course_level: Optional[str] = None
5656
course_format: Optional[str] = None
5757
instruction_language: Optional[str] = None
58+
# Certificate timestamps
59+
certificate_created_at: Optional[str] = None
60+
certificate_updated_at: Optional[str] = None
61+
# Student timestamps
62+
student_created_at: Optional[str] = None
63+
student_updated_at: Optional[str] = None
5864

5965

6066
class CertificateDeleteResponse(BaseModel):

backend/scripts/view_database.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,50 @@
11
import os
22
import sys
3+
from datetime import datetime, timezone
4+
5+
try:
6+
from dotenv import load_dotenv
7+
except ModuleNotFoundError:
8+
load_dotenv = None
39

4-
from dotenv import load_dotenv
510
from sqlalchemy.orm import Session
611

712
PROJECT_ROOT = os.path.dirname(os.path.dirname(__file__))
8-
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))
13+
if load_dotenv:
14+
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))
15+
else:
16+
# fallback: load simple KEY=VALUE pairs into env if .env exists
17+
env_path = os.path.join(PROJECT_ROOT, ".env")
18+
if os.path.exists(env_path):
19+
with open(env_path, "r", encoding="utf-8") as f:
20+
for raw in f:
21+
line = raw.strip()
22+
if not line or line.startswith("#") or "=" not in line:
23+
continue
24+
k, v = line.split("=", 1)
25+
os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))
26+
927
sys.path.append(PROJECT_ROOT)
1028

1129
from app import database
1230
from app.database import SessionLocal
1331
from app.models import Certificate
1432

1533

34+
def _format_dt(dt: datetime) -> str:
35+
if not dt:
36+
return "-"
37+
# ensure timezone-aware
38+
if dt.tzinfo is None:
39+
dt = dt.replace(tzinfo=timezone.utc)
40+
# convert to local timezone for display
41+
try:
42+
local = dt.astimezone()
43+
except Exception:
44+
local = dt
45+
return local.strftime("%d.%m.%Y, %H:%M %Z")
46+
47+
1648
def view_database(limit: int = 50):
1749
# Ensure missing optional columns are added before selecting all model fields.
1850
database.ensure_certificate_schema()
@@ -43,7 +75,7 @@ def view_database(limit: int = 50):
4375
print(f"Instructor : {cert.instructor}")
4476
print(f"Course Link : {cert.course_link or '-'}")
4577
print(f"Status : {getattr(cert, 'status', 'valid')}")
46-
print(f"Created At : {cert.created_at}")
78+
print(f"Created At : {_format_dt(cert.created_at)}")
4779
print("=" * 50)
4880

4981
except Exception as e:

0 commit comments

Comments
 (0)