MFF212 commited on
Commit
13933bf
·
verified ·
1 Parent(s): e1ce14b

Upload 16 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ # Set working directory
4
+ WORKDIR /app
5
+
6
+ # Copy requirements file and install dependencies
7
+ COPY requirements.txt .
8
+ RUN pip install --no-cache-dir -r requirements.txt
9
+
10
+ # Copy .env file into the container
11
+ COPY .env .
12
+
13
+ # Copy application code
14
+ COPY app/ app/
15
+ COPY run.py .
16
+
17
+ # Expose the port the app runs on
18
+ EXPOSE 8000
19
+
20
+ # Command to run the application
21
+ CMD ["python3", "run.py"]
app/__pycache__/main.cpython-313.pyc ADDED
Binary file (1.4 kB). View file
 
app/database/__pycache__/database.cpython-313.pyc ADDED
Binary file (2.7 kB). View file
 
app/database/database.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import create_engine
2
+ from sqlalchemy.ext.declarative import declarative_base
3
+ from sqlalchemy.orm import sessionmaker
4
+ import os
5
+ from dotenv import load_dotenv
6
+ import logging
7
+ import urllib.parse
8
+
9
+ # Configure logging
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Load environment variables
14
+ load_dotenv()
15
+
16
+ # Get database credentials from environment variables
17
+ DB_USER = os.getenv("DB_USER", "dev_cbs_admin")
18
+ DB_PASSWORD = os.getenv("DB_PASSWORD", "password")
19
+ DB_HOST = os.getenv("DB_HOST", "13.126.242.31")
20
+ DB_PORT = os.getenv("DB_PORT", "5432")
21
+ DB_NAME = os.getenv("DB_NAME", "vst")
22
+
23
+ # URL encode the password to handle special characters like @
24
+ encoded_password = urllib.parse.quote_plus(DB_PASSWORD)
25
+
26
+ # Log the connection parameters (without password)
27
+ logger.info(f"Attempting to connect to PostgreSQL database at {DB_HOST}:{DB_PORT}/{DB_NAME} as {DB_USER}")
28
+
29
+ # Create database URL for PostgreSQL with encoded password
30
+ SQLALCHEMY_DATABASE_URL = f"postgresql://{DB_USER}:{encoded_password}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
31
+ # Log the URL with password masked
32
+ masked_url = SQLALCHEMY_DATABASE_URL.replace(encoded_password, "****")
33
+ logger.info(f"Connection URL: {masked_url}")
34
+
35
+ try:
36
+ # Create engine
37
+ engine = create_engine(SQLALCHEMY_DATABASE_URL)
38
+
39
+ # Test connection
40
+ with engine.connect() as conn:
41
+ logger.info("Database connection successful")
42
+ except Exception as e:
43
+ logger.error(f"Database connection error: {e}")
44
+ # Create a SQLite engine as fallback for development/testing
45
+ logger.info("Using SQLite as fallback database")
46
+ SQLALCHEMY_DATABASE_URL = "sqlite:///./visitor_management.db"
47
+ engine = create_engine(
48
+ SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
49
+ )
50
+
51
+ # Create session
52
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
53
+
54
+ # Create base class
55
+ Base = declarative_base()
56
+
57
+ # Dependency to get DB session
58
+ def get_db():
59
+ db = SessionLocal()
60
+ try:
61
+ yield db
62
+ finally:
63
+ db.close()
app/main.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+
4
+ from app.database.database import engine
5
+ from app.models.models import Base
6
+ from app.routers import visitor_log, meeting_status, person_to_meet
7
+
8
+ # Create database tables
9
+ Base.metadata.create_all(bind=engine)
10
+
11
+ # Initialize FastAPI app
12
+ app = FastAPI(
13
+ title="Visitor Management System API",
14
+ description="API for managing visitor logs and meeting statuses",
15
+ version="1.0.0"
16
+ )
17
+
18
+ # Add CORS middleware
19
+ app.add_middleware(
20
+ CORSMiddleware,
21
+ allow_origins=["*"], # In production, replace with specific origins
22
+ allow_credentials=True,
23
+ allow_methods=["*"],
24
+ allow_headers=["*"],
25
+ )
26
+
27
+ # Include routers
28
+ app.include_router(visitor_log.router)
29
+ app.include_router(meeting_status.router)
30
+ app.include_router(person_to_meet.router)
31
+
32
+ @app.get("/")
33
+ def read_root():
34
+ return {"message": "Welcome to Visitor Management System API"}
app/models/__pycache__/models.cpython-313.pyc ADDED
Binary file (2.46 kB). View file
 
app/models/models.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
2
+ from sqlalchemy.orm import relationship
3
+ from app.database.database import Base
4
+
5
+ class VisitorLog(Base):
6
+ __tablename__ = "visitor_log"
7
+
8
+ sl_no = Column(Integer, primary_key=True, index=True, autoincrement=True)
9
+ full_name = Column(String(255), nullable=False)
10
+ email_address = Column(String(255), nullable=False)
11
+ phone_number = Column(String(20), nullable=False)
12
+ company_name = Column(String(255), nullable=True)
13
+ qid_id_number = Column(String(50), nullable=True)
14
+ purpose_of_visit = Column(String(500), nullable=False)
15
+ person_to_meet = Column(String(255), nullable=False)
16
+ preferred_datetime = Column(DateTime, nullable=False)
17
+ reference_number = Column(String(50), unique=True, nullable=False, index=True)
18
+
19
+ # Relationship with MeetingStatus
20
+ meeting_status = relationship("MeetingStatus", back_populates="visitor_log")
21
+
22
+ class MeetingStatus(Base):
23
+ __tablename__ = "meeting_status"
24
+
25
+ sl_no = Column(Integer, primary_key=True, index=True, autoincrement=True)
26
+ reference_number = Column(String(50), ForeignKey("visitor_log.reference_number"), nullable=False, unique=True)
27
+ status = Column(String(50), nullable=False)
28
+ email_send = Column(String(10), nullable=True) # Assuming this is a Yes/No or similar status
29
+
30
+ # Relationship with VisitorLog
31
+ visitor_log = relationship("VisitorLog", back_populates="meeting_status")
32
+
33
+ class PersonToMeet(Base):
34
+ __tablename__ = "person_to_meet"
35
+
36
+ id = Column(Integer, primary_key=True, index=True, autoincrement=True)
37
+ name = Column(String(255), nullable=False)
38
+ phone_number = Column(String(20), nullable=False, unique=True)
39
+ department = Column(String(255), nullable=False)
40
+ email_id = Column(String(255), nullable=False)
app/routers/__pycache__/meeting_status.cpython-313.pyc ADDED
Binary file (4.69 kB). View file
 
app/routers/__pycache__/person_to_meet.cpython-313.pyc ADDED
Binary file (3.99 kB). View file
 
app/routers/__pycache__/visitor_log.cpython-313.pyc ADDED
Binary file (4.58 kB). View file
 
app/routers/meeting_status.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends, HTTPException, status
2
+ from sqlalchemy.orm import Session
3
+ from typing import List
4
+
5
+ from app.database.database import get_db
6
+ from app.models.models import MeetingStatus, VisitorLog
7
+ from app.schemas.schemas import MeetingStatusCreate, MeetingStatusUpdate, MeetingStatusResponse
8
+
9
+ router = APIRouter(
10
+ prefix="/meeting-status",
11
+ tags=["meeting-status"]
12
+ )
13
+
14
+ # Create meeting status
15
+ @router.post("/", response_model=MeetingStatusResponse, status_code=status.HTTP_201_CREATED)
16
+ def create_meeting_status(meeting_status: MeetingStatusCreate, db: Session = Depends(get_db)):
17
+ # Check if visitor log exists
18
+ visitor_log = db.query(VisitorLog).filter(VisitorLog.reference_number == meeting_status.reference_number).first()
19
+ if not visitor_log:
20
+ raise HTTPException(status_code=404, detail="Visitor log not found")
21
+
22
+ # Check if meeting status already exists
23
+ existing_status = db.query(MeetingStatus).filter(MeetingStatus.reference_number == meeting_status.reference_number).first()
24
+ if existing_status:
25
+ raise HTTPException(status_code=400, detail="Meeting status already exists for this reference number")
26
+
27
+ db_meeting_status = MeetingStatus(
28
+ reference_number=meeting_status.reference_number,
29
+ status=meeting_status.status,
30
+ email_send=meeting_status.email_send
31
+ )
32
+ db.add(db_meeting_status)
33
+ db.commit()
34
+ db.refresh(db_meeting_status)
35
+ return db_meeting_status
36
+
37
+ # Get all meeting statuses
38
+ @router.get("/", response_model=List[MeetingStatusResponse])
39
+ def get_all_meeting_statuses(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
40
+ return db.query(MeetingStatus).offset(skip).limit(limit).all()
41
+
42
+ # Get meeting status by reference number
43
+ @router.get("/{reference_number}", response_model=MeetingStatusResponse)
44
+ def get_meeting_status(reference_number: str, db: Session = Depends(get_db)):
45
+ db_meeting_status = db.query(MeetingStatus).filter(MeetingStatus.reference_number == reference_number).first()
46
+ if db_meeting_status is None:
47
+ raise HTTPException(status_code=404, detail="Meeting status not found")
48
+ return db_meeting_status
49
+
50
+ # Update meeting status
51
+ @router.put("/{reference_number}", response_model=MeetingStatusResponse)
52
+ def update_meeting_status(reference_number: str, meeting_status: MeetingStatusUpdate, db: Session = Depends(get_db)):
53
+ db_meeting_status = db.query(MeetingStatus).filter(MeetingStatus.reference_number == reference_number).first()
54
+ if db_meeting_status is None:
55
+ raise HTTPException(status_code=404, detail="Meeting status not found")
56
+
57
+ # Update meeting status fields
58
+ for key, value in meeting_status.dict().items():
59
+ setattr(db_meeting_status, key, value)
60
+
61
+ db.commit()
62
+ db.refresh(db_meeting_status)
63
+ return db_meeting_status
64
+
65
+ # Delete meeting status
66
+ @router.delete("/{reference_number}", status_code=status.HTTP_204_NO_CONTENT)
67
+ def delete_meeting_status(reference_number: str, db: Session = Depends(get_db)):
68
+ db_meeting_status = db.query(MeetingStatus).filter(MeetingStatus.reference_number == reference_number).first()
69
+ if db_meeting_status is None:
70
+ raise HTTPException(status_code=404, detail="Meeting status not found")
71
+
72
+ db.delete(db_meeting_status)
73
+ db.commit()
74
+ return None
app/routers/person_to_meet.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends, HTTPException, status
2
+ from sqlalchemy.orm import Session
3
+ from typing import List
4
+
5
+ from app.database.database import get_db
6
+ from app.models.models import PersonToMeet
7
+ from app.schemas.schemas import PersonToMeetCreate, PersonToMeetUpdate, PersonToMeetResponse
8
+
9
+ router = APIRouter(
10
+ prefix="/person-to-meet",
11
+ tags=["person-to-meet"]
12
+ )
13
+
14
+ # Create person to meet
15
+ @router.post("/", response_model=PersonToMeetResponse, status_code=status.HTTP_201_CREATED)
16
+ def create_person_to_meet(person: PersonToMeetCreate, db: Session = Depends(get_db)):
17
+ db_person = PersonToMeet(
18
+ name=person.name,
19
+ phone_number=person.phone_number,
20
+ department=person.department,
21
+ email_id=person.email_id
22
+ )
23
+ db.add(db_person)
24
+ db.commit()
25
+ db.refresh(db_person)
26
+ return db_person
27
+
28
+ # Get all persons to meet
29
+ @router.get("/", response_model=List[PersonToMeetResponse])
30
+ def get_all_persons_to_meet(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
31
+ return db.query(PersonToMeet).offset(skip).limit(limit).all()
32
+
33
+ # Get person to meet by ID
34
+ @router.get("/{person_id}", response_model=PersonToMeetResponse)
35
+ def get_person_to_meet(person_id: int, db: Session = Depends(get_db)):
36
+ db_person = db.query(PersonToMeet).filter(PersonToMeet.id == person_id).first()
37
+ if db_person is None:
38
+ raise HTTPException(status_code=404, detail="Person to meet not found")
39
+ return db_person
40
+
41
+ # Update person to meet
42
+ @router.put("/{person_id}", response_model=PersonToMeetResponse)
43
+ def update_person_to_meet(person_id: int, person: PersonToMeetUpdate, db: Session = Depends(get_db)):
44
+ db_person = db.query(PersonToMeet).filter(PersonToMeet.id == person_id).first()
45
+ if db_person is None:
46
+ raise HTTPException(status_code=404, detail="Person to meet not found")
47
+
48
+ # Update person fields
49
+ for key, value in person.dict().items():
50
+ setattr(db_person, key, value)
51
+
52
+ db.commit()
53
+ db.refresh(db_person)
54
+ return db_person
55
+
56
+ # Delete person to meet
57
+ @router.delete("/{person_id}", status_code=status.HTTP_204_NO_CONTENT)
58
+ def delete_person_to_meet(person_id: int, db: Session = Depends(get_db)):
59
+ db_person = db.query(PersonToMeet).filter(PersonToMeet.id == person_id).first()
60
+ if db_person is None:
61
+ raise HTTPException(status_code=404, detail="Person to meet not found")
62
+
63
+ db.delete(db_person)
64
+ db.commit()
65
+ return None
app/routers/visitor_log.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends, HTTPException, status
2
+ from sqlalchemy.orm import Session
3
+ from typing import List
4
+ import uuid
5
+
6
+ from app.database.database import get_db
7
+ from app.models.models import VisitorLog
8
+ from app.schemas.schemas import VisitorLogCreate, VisitorLogResponse, VisitorWithStatusResponse
9
+
10
+ router = APIRouter(
11
+ prefix="/visitor-log",
12
+ tags=["visitor-log"]
13
+ )
14
+
15
+ # Generate unique reference number
16
+ def generate_reference_number():
17
+ return f"VST-{uuid.uuid4().hex[:8].upper()}"
18
+
19
+ # Create visitor log
20
+ @router.post("/", response_model=VisitorLogResponse, status_code=status.HTTP_201_CREATED)
21
+ def create_visitor_log(visitor: VisitorLogCreate, db: Session = Depends(get_db)):
22
+ reference_number = generate_reference_number()
23
+ db_visitor = VisitorLog(
24
+ full_name=visitor.full_name,
25
+ email_address=visitor.email_address,
26
+ phone_number=visitor.phone_number,
27
+ company_name=visitor.company_name,
28
+ qid_id_number=visitor.qid_id_number,
29
+ purpose_of_visit=visitor.purpose_of_visit,
30
+ person_to_meet=visitor.person_to_meet,
31
+ preferred_datetime=visitor.preferred_datetime,
32
+ reference_number=reference_number
33
+ )
34
+ db.add(db_visitor)
35
+ db.commit()
36
+ db.refresh(db_visitor)
37
+ return db_visitor
38
+
39
+ # Get all visitor logs
40
+ @router.get("/", response_model=List[VisitorLogResponse])
41
+ def get_all_visitor_logs(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
42
+ return db.query(VisitorLog).offset(skip).limit(limit).all()
43
+
44
+ # Get visitor log by reference number
45
+ @router.get("/{reference_number}", response_model=VisitorWithStatusResponse)
46
+ def get_visitor_log(reference_number: str, db: Session = Depends(get_db)):
47
+ db_visitor = db.query(VisitorLog).filter(VisitorLog.reference_number == reference_number).first()
48
+ if db_visitor is None:
49
+ raise HTTPException(status_code=404, detail="Visitor log not found")
50
+ return db_visitor
51
+
52
+ # Update visitor log
53
+ @router.put("/{reference_number}", response_model=VisitorLogResponse)
54
+ def update_visitor_log(reference_number: str, visitor: VisitorLogCreate, db: Session = Depends(get_db)):
55
+ db_visitor = db.query(VisitorLog).filter(VisitorLog.reference_number == reference_number).first()
56
+ if db_visitor is None:
57
+ raise HTTPException(status_code=404, detail="Visitor log not found")
58
+
59
+ # Update visitor log fields
60
+ for key, value in visitor.dict().items():
61
+ setattr(db_visitor, key, value)
62
+
63
+ db.commit()
64
+ db.refresh(db_visitor)
65
+ return db_visitor
66
+
67
+ # Delete visitor log
68
+ @router.delete("/{reference_number}", status_code=status.HTTP_204_NO_CONTENT)
69
+ def delete_visitor_log(reference_number: str, db: Session = Depends(get_db)):
70
+ db_visitor = db.query(VisitorLog).filter(VisitorLog.reference_number == reference_number).first()
71
+ if db_visitor is None:
72
+ raise HTTPException(status_code=404, detail="Visitor log not found")
73
+
74
+ db.delete(db_visitor)
75
+ db.commit()
76
+ return None
app/schemas/__pycache__/schemas.cpython-313.pyc ADDED
Binary file (4.13 kB). View file
 
app/schemas/schemas.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, EmailStr, Field
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ # VisitorLog Schemas
6
+ class VisitorLogBase(BaseModel):
7
+ full_name: str
8
+ email_address: EmailStr
9
+ phone_number: str
10
+ company_name: Optional[str] = None
11
+ qid_id_number: Optional[str] = None
12
+ purpose_of_visit: str
13
+ person_to_meet: str
14
+ preferred_datetime: datetime
15
+
16
+ class VisitorLogCreate(VisitorLogBase):
17
+ pass
18
+
19
+ class VisitorLogResponse(VisitorLogBase):
20
+ sl_no: int
21
+ reference_number: str
22
+
23
+ class Config:
24
+ from_attributes = True # Updated from orm_mode
25
+
26
+ # MeetingStatus Schemas
27
+ class MeetingStatusBase(BaseModel):
28
+ status: str
29
+ email_send: Optional[str] = None
30
+
31
+ class MeetingStatusCreate(MeetingStatusBase):
32
+ reference_number: str
33
+
34
+ class MeetingStatusUpdate(MeetingStatusBase):
35
+ pass
36
+
37
+ class MeetingStatusResponse(MeetingStatusBase):
38
+ sl_no: int
39
+ reference_number: str
40
+
41
+ class Config:
42
+ from_attributes = True # Updated from orm_mode
43
+
44
+ # Combined Response Schema
45
+ class VisitorWithStatusResponse(VisitorLogResponse):
46
+ meeting_status: Optional[MeetingStatusResponse] = None
47
+
48
+ class Config:
49
+ from_attributes = True # Updated from orm_mode
50
+
51
+ # PersonToMeet Schemas
52
+ class PersonToMeetBase(BaseModel):
53
+ name: str
54
+ phone_number: str
55
+ department: str
56
+ email_id: EmailStr
57
+
58
+ class PersonToMeetCreate(PersonToMeetBase):
59
+ pass
60
+
61
+ class PersonToMeetUpdate(PersonToMeetBase):
62
+ pass
63
+
64
+ class PersonToMeetResponse(PersonToMeetBase):
65
+ id: int
66
+
67
+ class Config:
68
+ from_attributes = True
run.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import uvicorn
2
+
3
+ if __name__ == "__main__":
4
+ uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)