app.models
Data model definitions for Vision Hub.
All models are defined using SQLAlchemy ORM and represent the database schema for the application.
Models include:
- User: Represents a user in the system with self-referential relationships for managers.
- Role: Represents user roles (e.g., admin, manager, staff).
- Department: Represents departments within the organization.
- TrainingModule: Represents training modules with associated questions and user progress.
- Question: Represents questions within training modules.
- Option: Represents answer options for questions.
- UserModuleProgress: Tracks user progress in training modules.
- UserQuestionAnswer: Represents answers submitted by users to questions.
- OnboardingPath: Represents onboarding paths for different staff types.
- OnboardingStep: Represents steps in an onboarding path, such as training modules.
- DocumentRepository: Represents documents in the repository.
- Report: Represents reports generated in the system.
1# The database for this application was developed with the support of Miguel 2# Grinberg's The Flash Mega Tutorial series 3# https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database 4 5"""Data model definitions for Vision Hub. 6 7 All models are defined using SQLAlchemy ORM and represent the database schema 8 for the application. 9 10 Models include: 11 - User: Represents a user in the system with self-referential 12 relationships for managers. 13 - Role: Represents user roles (e.g., admin, manager, staff). 14 - Department: Represents departments within the organization. 15 - TrainingModule: Represents training modules with associated 16 questions and user progress. 17 - Question: Represents questions within training modules. 18 - Option: Represents answer options for questions. 19 - UserModuleProgress: Tracks user progress in training modules. 20 - UserQuestionAnswer: Represents answers submitted by users to questions. 21 - OnboardingPath: Represents onboarding paths for different staff types. 22 - OnboardingStep: Represents steps in an onboarding path, such as 23 training modules. 24 - DocumentRepository: Represents documents in the repository. 25 - Report: Represents reports generated in the system. 26""" 27from datetime import datetime, timezone 28from typing import Optional, List 29 30from flask_login import UserMixin 31import sqlalchemy as sa 32import sqlalchemy.orm as so 33from sqlalchemy import Boolean 34from werkzeug.security import generate_password_hash, check_password_hash 35 36from app import db, login 37 38 39class User(UserMixin, db.Model): 40 """ 41 Represents a user in the system. 42 43 Attributes: 44 id (int): Primary key. 45 username (str): Unique login identifier (email). 46 first_name (str): The user's first name. 47 surname (str): The user's last name. 48 job_title (str): The user's position title. 49 password_hash (str): Hashed password for authentication. 50 is_onboarding (bool): Flag indicating whether the user is in onboarding. 51 dateStarted (datetime): Timestamp when the user account was created. 52 google_email (Optional[str]): Optional linked Google account email. 53 profile_photo (Optional[str]): Optional profile photo filename. 54 manager_id (Optional[int]): Foreign key to another User (their manager). 55 manager (User): The user's manager (self-referential relationship). 56 manages (list[User]): List of users managed by this user. 57 role_id (int): Foreign key to the Role model. 58 role (Role): The role assigned to the user. 59 department_id (int): Foreign key to the Department model. 60 department (Department): The department assigned to the user. 61 module_progress (list[UserModuleProgress]): List of training module 62 progress entries for this user. 63 onboarding_path_id (Optional[int]): Foreign key to an OnboardingPath. 64 onboarding_path (OnboardingPath): The onboarding path assigned to the user. 65 """ 66 __tablename__ = 'user' 67 68 # Primary key 69 id: so.Mapped[int] = so.mapped_column(primary_key = True) 70 71 # User details 72 username: so.Mapped[str] = so.mapped_column( 73 sa.String(120), 74 index = True, 75 unique = True 76 ) 77 first_name: so.Mapped[str] = so.mapped_column( 78 sa.String(50), 79 index = True 80 ) 81 surname: so.Mapped[str] = so.mapped_column( 82 sa.String(50), 83 index = True 84 ) 85 job_title: so.Mapped[str] = so.mapped_column( 86 sa.String(50), 87 index = True 88 ) 89 password_hash: so.Mapped[str] = so.mapped_column( 90 sa.String(256) 91 ) 92 is_onboarding: so.Mapped[bool] = so.mapped_column( 93 default = False # Default: Not onboarding 94 ) 95 dateStarted: so.Mapped[datetime] = so.mapped_column( 96 index=True, 97 default = lambda: 98 datetime.now(timezone.utc) 99 ) 100 google_email: so.Mapped[Optional[str]] = so.mapped_column( 101 sa.String(120), 102 unique = True, 103 nullable = True 104 ) 105 profile_photo: so.Mapped[Optional[str]] = so.mapped_column( 106 sa.String(120), 107 nullable = True, 108 default = 'profileDefault.png' 109 ) 110 111 # Self-referential relationship for manager and those managed 112 manager_id: so.Mapped[Optional[int]] = so.mapped_column( 113 sa.ForeignKey('user.id'), 114 nullable = True 115 ) 116 manager: so.Mapped[Optional['User']] = so.relationship( 117 'User', 118 remote_side=[id], 119 back_populates = 'manages' 120 ) 121 manages: so.Mapped[List['User']] = so.relationship( 122 'User', 123 back_populates = 'manager' 124 ) 125 126 # Relationship to role 127 role_id: so.Mapped[int] = so.mapped_column( 128 sa.ForeignKey('role.id') 129 ) 130 role: so.Mapped['Role'] = so.relationship( 131 'Role', 132 back_populates = 'users' 133 ) 134 135 # Relationship to department 136 department_id: so.Mapped[int] = so.mapped_column( 137 sa.ForeignKey('department.id') 138 ) 139 department: so.Mapped['Department'] = so.relationship( 140 'Department', 141 back_populates = 'users' 142 ) 143 144 # Relationship to module progress 145 module_progress: so.Mapped[List['UserModuleProgress']] = so.relationship( 146 'UserModuleProgress', back_populates = 'user' 147 ) 148 149 # Relationship to onboarding path 150 onboarding_path_id: so.Mapped[int] = so.mapped_column( 151 sa.ForeignKey('onboarding_path.id'), 152 nullable = True 153 ) 154 onboarding_path: so.Mapped['OnboardingPath'] = so.relationship( 155 'OnboardingPath' 156 ) 157 158 def __repr__(self): 159 """Returns a string representation of the User object.""" 160 return f'<User {self.username}>' 161 162 def set_password(self, password): 163 """Sets the user's password by hashing it.""" 164 self.password_hash = generate_password_hash(password) 165 166 def check_password(self, password): 167 """Verifies the user's password matched the stored hashed password.""" 168 return check_password_hash(self.password_hash, password) 169 170 171@login.user_loader 172def load_user(id): 173 """Loads a user by their ID for Flask-Login session management. 174 175 Args: 176 id (int): The unique identifier of the user. 177 178 Returns: 179 User: The User object or None if not found. 180 """ 181 return db.session.get(User, int(id)) 182 183 184class Role(db.Model): 185 """Represents a role in the system. 186 187 Attributes: 188 id (int): Primary key. 189 role_name (str): Name of the role (e.g., admin, manager, staff). 190 users (list[User]): List of users assigned to this role (relationship). 191 """ 192 __tablename__ = 'role' 193 194 # Primary key 195 id: so.Mapped[int] = so.mapped_column(primary_key=True) 196 197 # Role details 198 role_name: so.Mapped[str] = so.mapped_column( 199 sa.String(20), 200 index = True, 201 unique = True 202 ) 203 204 # Relationship to User 205 users: so.Mapped[list['User']] = so.relationship( 206 'User', back_populates = 'role' 207 ) 208 209 def __repr__(self): 210 """Returns a string representation of the Role object.""" 211 return f'<Role {self.role_name}>' 212 213 214class Department(db.Model): 215 """Represents a department in the system. 216 217 Attributes: 218 id (int): Primary key. 219 department_name (str): Name of the department (e.g., office, operational). 220 users (list[User]): List of users assigned to this department. 221 """ 222 __tablename__ = 'department' 223 224 # Primary key 225 id: so.Mapped[int] = so.mapped_column( 226 primary_key = True 227 ) 228 229 # Department details 230 department_name: so.Mapped[str] = so.mapped_column( 231 sa.String(20), 232 index = True, 233 unique = True 234 ) 235 236 # Relationship to User 237 users: so.Mapped[List['User']] = so.relationship( 238 'User', 239 back_populates = 'department' 240 ) 241 242 def __repr__(self): 243 """Returns a string representation of the Department object.""" 244 return f'<Department {self.department_name}>' 245 246 247class TrainingModule (db.Model): 248 """Represents a training module in the system. 249 250 Attributes: 251 id (int): Primary key. 252 module_title (str): Title of the module. 253 module_description (str): Detailed description. 254 module_instructions (str): Instructions for completing the module. 255 video_url (Optional[str]): Optional URL for video content. 256 active (bool): Indicates whether the module is currently active. 257 questions (list[Question]): Questions associated with the module. 258 user_progress (list[UserModuleProgress]): Progress entries for users. 259 onboarding_steps (List[OnboardingStep]): Steps in assigned onboarding 260 paths. 261 """ 262 __tablename__ = 'training_module' 263 264 # Primary key 265 id: so.Mapped[int] = so.mapped_column(primary_key=True) 266 267 # Training module details 268 module_title: so.Mapped[str] = so.mapped_column( 269 sa.String(150), index=True, unique=True 270 ) 271 module_description: so.Mapped[str] = so.mapped_column( 272 sa.Text, nullable=False 273 ) 274 module_instructions: so.Mapped[str] = so.mapped_column( 275 sa.Text, nullable=False 276 ) 277 video_url: so.Mapped[str] = so.mapped_column( 278 sa.String(300), nullable=True 279 ) 280 active: so.Mapped[bool] = so.mapped_column( 281 sa.Boolean, nullable=False, default=True 282 ) 283 284 # Relationship with questions 285 questions: so.Mapped[List['Question']] = so.relationship( 286 'Question', 287 back_populates = 'training_module', 288 cascade = 'all, delete-orphan') 289 290 # Relationship with user progress 291 user_progress: so.Mapped[List['UserModuleProgress']] = so.relationship( 292 'UserModuleProgress', 293 back_populates = 'training_module' 294 ) 295 296 # Relationship with onboarding steps 297 onboarding_steps: so.Mapped[List['OnboardingStep']] = so.relationship( 298 'OnboardingStep', 299 back_populates = 'training_module', 300 cascade = 'all, delete-orphan' 301 ) 302 303 def __repr__(self): 304 """Returns a string representation of the TrainingModule object.""" 305 return f'<TrainingModule {self.module_title}>' 306 307 308class Question (db.Model): 309 """Represents a question in the system. 310 311 Attributes: 312 id (int): Primary key. 313 question_text (str): The text of the question. 314 training_module_id (int): Foreign key to TrainingModule. 315 training_module (TrainingModule): Associated training module. 316 options (list[Option]): List of answer choices for this question. 317 """ 318 __tablename__ = 'question' 319 320 # Primary key 321 id: so.Mapped[int] = so.mapped_column(primary_key=True) 322 323 # Question details 324 question_text: so.Mapped[str] = so.mapped_column( 325 sa.String(1000), 326 nullable=False 327 ) 328 329 # Relationship with training module id 330 training_module_id: so.Mapped[int] = so.mapped_column( 331 sa.ForeignKey('training_module.id'), 332 nullable=False 333 ) 334 training_module: so.Mapped['TrainingModule'] = so.relationship( 335 'TrainingModule', 336 back_populates = 'questions') 337 338 # Relationship with options 339 options: so.Mapped[List['Option']] = so.relationship( 340 'Option', 341 back_populates = 'question', 342 cascade='all, delete-orphan' 343 ) 344 345 def __repr__(self): 346 """Returns a string representation of the Question object.""" 347 return f'<Question {self.question_text}>' 348 349 350class Option (db.Model): 351 """Represents answer options for a question. 352 353 Attributes: 354 id (int): Primary key. 355 question_id (int): Foreign key to the question. 356 option_text (str): The text of this option. 357 is_correct (bool): True if this option is the correct answer. 358 question (Question): The associated question. 359 """ 360 __tablename__ = "option" 361 362 # Primary key 363 id: so.Mapped[int] = so.mapped_column(primary_key=True) 364 365 # Option details 366 question_id: so.Mapped[int] = so.mapped_column( 367 sa.ForeignKey('question.id'), 368 nullable=False 369 ) 370 option_text: so.Mapped[str] = so.mapped_column( 371 sa.String(500), 372 nullable=False 373 ) 374 is_correct: so.Mapped[bool] = so.mapped_column( 375 sa.Boolean, 376 default=False, 377 nullable=False 378 ) 379 380 # Relationship with question 381 question: so.Mapped['Question'] = so.relationship( 382 'Question', 383 back_populates = 'options' 384 ) 385 386 def __repr__(self): 387 """Returns a string representation of the Option object.""" 388 return f'<Option {self.option_text}>' 389 390 391class UserModuleProgress (db.Model): 392 """ 393 Represents the progress of a user in a training module. 394 395 Attributes: 396 id (int): Primary key. 397 start_date (datetime): When the module was started. 398 completed_date (datetime, optional): When the module was completed. 399 score (int, optional): The score achieved by the user in the module. 400 attempts (int): Number of attempts made by the user. 401 user_id (int): Foreign key to the User model. 402 user (User): The user associated with this progress entry. 403 training_module_id (int): Foreign key to the TrainingModule model. 404 training_module (TrainingModule): The training module associated with 405 this progress entry. 406 answers (list[UserQuestionAnswer]): Answers submitted during this attempt. 407 """ 408 __tablename__ = 'user_module_progress' 409 410 # Primary key 411 id: so.Mapped[int] = so.mapped_column(primary_key=True) 412 413 # User Module Progress details 414 start_date: so.Mapped[datetime] = so.mapped_column( 415 sa.DateTime, 416 default = lambda: datetime.now(timezone.utc), 417 nullable = False 418 ) 419 completed_date: so.Mapped[datetime] = so.mapped_column( 420 sa.DateTime, 421 nullable = True 422 ) 423 score: so.Mapped[int] = so.mapped_column( 424 sa.Integer, 425 nullable = True 426 ) 427 attempts: so.Mapped[int] = so.mapped_column( 428 sa.Integer, 429 default=0, 430 nullable = False 431 ) 432 433 # Relationship to User 434 user_id: so.Mapped[int] = so.mapped_column( 435 sa.ForeignKey('user.id'), 436 nullable = False 437 ) 438 user: so.Mapped['User'] = so.relationship( 439 'User', 440 back_populates = 'module_progress' 441 ) 442 443 # Relationship to Training Module 444 training_module_id: so.Mapped[int] = so.mapped_column( 445 sa.ForeignKey('training_module.id'), 446 nullable = False 447 ) 448 training_module: so.Mapped['TrainingModule'] = so.relationship( 449 'TrainingModule', 450 back_populates = 'user_progress' 451 ) 452 453 # Relationship to User Question Answer 454 answers: so.Mapped[List['UserQuestionAnswer']] = so.relationship( 455 'UserQuestionAnswer', 456 back_populates = 'progress', 457 cascade = 'all, delete-orphan' 458 ) 459 460 461class UserQuestionAnswer (db.Model): 462 """Represents an answer submitted by a user to a specific question. 463 464 Attributes: 465 id (int): Primary key. 466 is_correct (bool): True if the selected option was correct. 467 progress_id (int): Foreign key to the UserModuleProgress model. 468 progress (UserModuleProgress): Relationship to the user's progress 469 record. 470 question_id (int): Foreign key to the Question. 471 question (Question): Question associated with this answer. 472 selected_option_id (int, optional): Foreign key to the chosen Option. 473 selected_option (Option, optional): Relationship to the selected 474 Option (if any). 475 """ 476 __tablename__ = 'user_question_answer' 477 478 # Primary key 479 id: so.Mapped[int] = so.mapped_column(primary_key=True) 480 is_correct: so.Mapped[bool] = so.mapped_column(sa.Boolean) 481 482 # User Question Answer details 483 progress_id: so.Mapped[int] = so.mapped_column( 484 sa.ForeignKey('user_module_progress.id'), 485 nullable = False 486 ) 487 488 # Relationship to User Module Progress 489 progress: so.Mapped['UserModuleProgress'] = so.relationship( 490 'UserModuleProgress', 491 back_populates = 'answers' 492 ) 493 494 # Relationship to question 495 question_id: so.Mapped[int] = so.mapped_column( 496 sa.ForeignKey('question.id'), 497 nullable = False 498 ) 499 question: so.Mapped['Question'] = so.relationship('Question') 500 501 # Relationship to option 502 selected_option_id: so.Mapped[int] = so.mapped_column( 503 sa.ForeignKey('option.id'), 504 nullable = True 505 ) 506 selected_option: so.Mapped['Option'] = so.relationship('Option') 507 508 509class OnboardingPath(db.Model): 510 """Represents an onboarding path defining a sequence of steps for staff. 511 512 Attributes: 513 id (int): Primary key. 514 path_name (str): Name of the onboarding path (e.g., “office”, 515 “operational”). 516 steps (list[OnboardingStep]): Ordered steps in this path. 517 """ 518 __tablename__ = 'onboarding_path' 519 520 # Primary key 521 id: so.Mapped[int] = so.mapped_column(primary_key=True) 522 523 #Onboarding path details 524 path_name: so.Mapped[str] = so.mapped_column( 525 sa.String(100), 526 nullable=False, 527 unique=True 528 ) 529 530 # Relationship with onboarding steps 531 steps: so.Mapped[List['OnboardingStep']] = so.relationship( 532 'OnboardingStep', 533 back_populates='path', 534 cascade='all, delete-orphan' 535 ) 536 537 def __repr__(self): 538 """Returns a string representation of the Onboarding Path object.""" 539 return f"<OnboardingPath {self.path_name}>" 540 541 542class OnboardingStep(db.Model): 543 """Step within an onboarding path, e.g. a training module or task. 544 545 Attributes: 546 id (int): Primary key. 547 step_name (str): Name of this step. 548 onboarding_path_id (int): Foreign key to the OnboardingPath. 549 path (OnboardingPath): Relationship back to the parent path. 550 training_module_id (int, optional): Foreign key to the TrainingModule, 551 if any. 552 training_module (TrainingModule): The training module associated with 553 this step. 554 """ 555 __tablename__ = 'onboarding_step' 556 557 # Primary key 558 id: so.Mapped[int] = so.mapped_column(primary_key = True) 559 560 # Onboarding Step details 561 step_name: so.Mapped[str] = so.mapped_column( 562 sa.String(150), 563 nullable = False 564 ) 565 566 # Relationship to Onboarding Path 567 onboarding_path_id: so.Mapped[int] = so.mapped_column( 568 sa.ForeignKey('onboarding_path.id'), 569 nullable = False 570 ) 571 path: so.Mapped['OnboardingPath'] = so.relationship( 572 'OnboardingPath', 573 back_populates = 'steps' 574 ) 575 576 # Relationship to training modules 577 training_module_id: so.Mapped[int] = so.mapped_column( 578 sa.ForeignKey('training_module.id'), 579 nullable = True 580 ) 581 training_module: so.Mapped['TrainingModule'] = so.relationship( 582 'TrainingModule', 583 back_populates = 'onboarding_steps' 584 ) 585 586 def __repr__(self): 587 """Returns a string representation of the OnboardingStep object.""" 588 return f"<OnboardingStep {self.step_name}>" 589 590 591class DocumentRepository(db.Model): 592 """Represents a document in the repository. 593 594 Attributes: 595 id (int): Primary key. 596 document_title (str): Title of the document. 597 document_category (str): Category of the document (e.g., Policy, Guide, 598 Form). 599 upload_date (datetime): Timestamp when uploaded. 600 file_path (str): Filesystem path to the uploaded file. 601 user_id (int): Foreign key to the uploaders User model. 602 uploaded_by_user (User): The user who uploaded the document. 603 """ 604 __tablename__ = 'document_repository' 605 606 # Primary key 607 id: so.Mapped[int] = so.mapped_column(primary_key=True) 608 609 # Repository details 610 document_title: so.Mapped[str] = so.mapped_column( 611 sa.String(150), 612 nullable = False 613 ) 614 document_category: so.Mapped[str] = so.mapped_column( 615 sa.Enum('Policy', 'Guide', 'Form', 616 name = 'document_category'), 617 nullable = False 618 ) 619 upload_date: so.Mapped[datetime] = so.mapped_column( 620 sa.DateTime, 621 default=lambda: datetime.now(timezone.utc), 622 nullable = False 623 ) 624 file_path: so.Mapped[str] = so.mapped_column( 625 sa.String(300), 626 nullable = False 627 ) 628 629 # Relationship to User 630 user_id: so.Mapped[int] = so.mapped_column( 631 sa.ForeignKey('user.id'), 632 nullable = False 633 ) 634 uploaded_by_user: so.Mapped['User'] = so.relationship('User') 635 636 def __repr__(self): 637 """Returns a string representation of the Document Repository object.""" 638 return f"<DocumentRepository {self.document_title}>" 639 640 641class Report(db.Model): 642 """Represents a report in the system. 643 644 Attributes: 645 id (int): Primary key. 646 report_type (str): Type of report (e.g., Completion, Performance). 647 description (str): Short description of the report. 648 report_data (str, optional): Stored Json report content. 649 created_at (datetime): Timestamp when the report was created. 650 """ 651 __tablename__ = 'report' 652 653 # Primary key 654 id: so.Mapped[int] = so.mapped_column(primary_key=True) 655 656 # Report details 657 report_type: so.Mapped[str] = so.mapped_column( 658 sa.Enum('Completion', 'Performance', name = 'report_type'), 659 nullable = False 660 ) 661 description: so.Mapped[str] = so.mapped_column( 662 sa.String(255), 663 nullable = False 664 ) 665 report_data: so.Mapped[Optional[str]] = so.mapped_column( 666 sa.Text, 667 nullable = True) 668 created_at: so.Mapped[datetime] = so.mapped_column( 669 sa.DateTime, 670 default = lambda: datetime.now(timezone.utc), 671 nullable = False 672 ) 673 674 def __repr__(self): 675 """Returns a string representation of the Report object.""" 676 return f"<Report {self.report_type} created on {self.created_at}>"
40class User(UserMixin, db.Model): 41 """ 42 Represents a user in the system. 43 44 Attributes: 45 id (int): Primary key. 46 username (str): Unique login identifier (email). 47 first_name (str): The user's first name. 48 surname (str): The user's last name. 49 job_title (str): The user's position title. 50 password_hash (str): Hashed password for authentication. 51 is_onboarding (bool): Flag indicating whether the user is in onboarding. 52 dateStarted (datetime): Timestamp when the user account was created. 53 google_email (Optional[str]): Optional linked Google account email. 54 profile_photo (Optional[str]): Optional profile photo filename. 55 manager_id (Optional[int]): Foreign key to another User (their manager). 56 manager (User): The user's manager (self-referential relationship). 57 manages (list[User]): List of users managed by this user. 58 role_id (int): Foreign key to the Role model. 59 role (Role): The role assigned to the user. 60 department_id (int): Foreign key to the Department model. 61 department (Department): The department assigned to the user. 62 module_progress (list[UserModuleProgress]): List of training module 63 progress entries for this user. 64 onboarding_path_id (Optional[int]): Foreign key to an OnboardingPath. 65 onboarding_path (OnboardingPath): The onboarding path assigned to the user. 66 """ 67 __tablename__ = 'user' 68 69 # Primary key 70 id: so.Mapped[int] = so.mapped_column(primary_key = True) 71 72 # User details 73 username: so.Mapped[str] = so.mapped_column( 74 sa.String(120), 75 index = True, 76 unique = True 77 ) 78 first_name: so.Mapped[str] = so.mapped_column( 79 sa.String(50), 80 index = True 81 ) 82 surname: so.Mapped[str] = so.mapped_column( 83 sa.String(50), 84 index = True 85 ) 86 job_title: so.Mapped[str] = so.mapped_column( 87 sa.String(50), 88 index = True 89 ) 90 password_hash: so.Mapped[str] = so.mapped_column( 91 sa.String(256) 92 ) 93 is_onboarding: so.Mapped[bool] = so.mapped_column( 94 default = False # Default: Not onboarding 95 ) 96 dateStarted: so.Mapped[datetime] = so.mapped_column( 97 index=True, 98 default = lambda: 99 datetime.now(timezone.utc) 100 ) 101 google_email: so.Mapped[Optional[str]] = so.mapped_column( 102 sa.String(120), 103 unique = True, 104 nullable = True 105 ) 106 profile_photo: so.Mapped[Optional[str]] = so.mapped_column( 107 sa.String(120), 108 nullable = True, 109 default = 'profileDefault.png' 110 ) 111 112 # Self-referential relationship for manager and those managed 113 manager_id: so.Mapped[Optional[int]] = so.mapped_column( 114 sa.ForeignKey('user.id'), 115 nullable = True 116 ) 117 manager: so.Mapped[Optional['User']] = so.relationship( 118 'User', 119 remote_side=[id], 120 back_populates = 'manages' 121 ) 122 manages: so.Mapped[List['User']] = so.relationship( 123 'User', 124 back_populates = 'manager' 125 ) 126 127 # Relationship to role 128 role_id: so.Mapped[int] = so.mapped_column( 129 sa.ForeignKey('role.id') 130 ) 131 role: so.Mapped['Role'] = so.relationship( 132 'Role', 133 back_populates = 'users' 134 ) 135 136 # Relationship to department 137 department_id: so.Mapped[int] = so.mapped_column( 138 sa.ForeignKey('department.id') 139 ) 140 department: so.Mapped['Department'] = so.relationship( 141 'Department', 142 back_populates = 'users' 143 ) 144 145 # Relationship to module progress 146 module_progress: so.Mapped[List['UserModuleProgress']] = so.relationship( 147 'UserModuleProgress', back_populates = 'user' 148 ) 149 150 # Relationship to onboarding path 151 onboarding_path_id: so.Mapped[int] = so.mapped_column( 152 sa.ForeignKey('onboarding_path.id'), 153 nullable = True 154 ) 155 onboarding_path: so.Mapped['OnboardingPath'] = so.relationship( 156 'OnboardingPath' 157 ) 158 159 def __repr__(self): 160 """Returns a string representation of the User object.""" 161 return f'<User {self.username}>' 162 163 def set_password(self, password): 164 """Sets the user's password by hashing it.""" 165 self.password_hash = generate_password_hash(password) 166 167 def check_password(self, password): 168 """Verifies the user's password matched the stored hashed password.""" 169 return check_password_hash(self.password_hash, password)
Represents a user in the system.
Attributes:
- id (int): Primary key.
- username (str): Unique login identifier (email).
- first_name (str): The user's first name.
- surname (str): The user's last name.
- job_title (str): The user's position title.
- password_hash (str): Hashed password for authentication.
- is_onboarding (bool): Flag indicating whether the user is in onboarding.
- dateStarted (datetime): Timestamp when the user account was created.
- google_email (Optional[str]): Optional linked Google account email.
- profile_photo (Optional[str]): Optional profile photo filename.
- manager_id (Optional[int]): Foreign key to another User (their manager).
- manager (User): The user's manager (self-referential relationship).
- manages (list[User]): List of users managed by this user.
- role_id (int): Foreign key to the Role model.
- role (Role): The role assigned to the user.
- department_id (int): Foreign key to the Department model.
- department (Department): The department assigned to the user.
- module_progress (list[UserModuleProgress]): List of training module progress entries for this user.
- onboarding_path_id (Optional[int]): Foreign key to an OnboardingPath.
- onboarding_path (OnboardingPath): The onboarding path assigned to the user.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
172@login.user_loader 173def load_user(id): 174 """Loads a user by their ID for Flask-Login session management. 175 176 Args: 177 id (int): The unique identifier of the user. 178 179 Returns: 180 User: The User object or None if not found. 181 """ 182 return db.session.get(User, int(id))
Loads a user by their ID for Flask-Login session management.
Arguments:
- id (int): The unique identifier of the user.
Returns:
User: The User object or None if not found.
185class Role(db.Model): 186 """Represents a role in the system. 187 188 Attributes: 189 id (int): Primary key. 190 role_name (str): Name of the role (e.g., admin, manager, staff). 191 users (list[User]): List of users assigned to this role (relationship). 192 """ 193 __tablename__ = 'role' 194 195 # Primary key 196 id: so.Mapped[int] = so.mapped_column(primary_key=True) 197 198 # Role details 199 role_name: so.Mapped[str] = so.mapped_column( 200 sa.String(20), 201 index = True, 202 unique = True 203 ) 204 205 # Relationship to User 206 users: so.Mapped[list['User']] = so.relationship( 207 'User', back_populates = 'role' 208 ) 209 210 def __repr__(self): 211 """Returns a string representation of the Role object.""" 212 return f'<Role {self.role_name}>'
Represents a role in the system.
Attributes:
- id (int): Primary key.
- role_name (str): Name of the role (e.g., admin, manager, staff).
- users (list[User]): List of users assigned to this role (relationship).
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
215class Department(db.Model): 216 """Represents a department in the system. 217 218 Attributes: 219 id (int): Primary key. 220 department_name (str): Name of the department (e.g., office, operational). 221 users (list[User]): List of users assigned to this department. 222 """ 223 __tablename__ = 'department' 224 225 # Primary key 226 id: so.Mapped[int] = so.mapped_column( 227 primary_key = True 228 ) 229 230 # Department details 231 department_name: so.Mapped[str] = so.mapped_column( 232 sa.String(20), 233 index = True, 234 unique = True 235 ) 236 237 # Relationship to User 238 users: so.Mapped[List['User']] = so.relationship( 239 'User', 240 back_populates = 'department' 241 ) 242 243 def __repr__(self): 244 """Returns a string representation of the Department object.""" 245 return f'<Department {self.department_name}>'
Represents a department in the system.
Attributes:
- id (int): Primary key.
- department_name (str): Name of the department (e.g., office, operational).
- users (list[User]): List of users assigned to this department.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
248class TrainingModule (db.Model): 249 """Represents a training module in the system. 250 251 Attributes: 252 id (int): Primary key. 253 module_title (str): Title of the module. 254 module_description (str): Detailed description. 255 module_instructions (str): Instructions for completing the module. 256 video_url (Optional[str]): Optional URL for video content. 257 active (bool): Indicates whether the module is currently active. 258 questions (list[Question]): Questions associated with the module. 259 user_progress (list[UserModuleProgress]): Progress entries for users. 260 onboarding_steps (List[OnboardingStep]): Steps in assigned onboarding 261 paths. 262 """ 263 __tablename__ = 'training_module' 264 265 # Primary key 266 id: so.Mapped[int] = so.mapped_column(primary_key=True) 267 268 # Training module details 269 module_title: so.Mapped[str] = so.mapped_column( 270 sa.String(150), index=True, unique=True 271 ) 272 module_description: so.Mapped[str] = so.mapped_column( 273 sa.Text, nullable=False 274 ) 275 module_instructions: so.Mapped[str] = so.mapped_column( 276 sa.Text, nullable=False 277 ) 278 video_url: so.Mapped[str] = so.mapped_column( 279 sa.String(300), nullable=True 280 ) 281 active: so.Mapped[bool] = so.mapped_column( 282 sa.Boolean, nullable=False, default=True 283 ) 284 285 # Relationship with questions 286 questions: so.Mapped[List['Question']] = so.relationship( 287 'Question', 288 back_populates = 'training_module', 289 cascade = 'all, delete-orphan') 290 291 # Relationship with user progress 292 user_progress: so.Mapped[List['UserModuleProgress']] = so.relationship( 293 'UserModuleProgress', 294 back_populates = 'training_module' 295 ) 296 297 # Relationship with onboarding steps 298 onboarding_steps: so.Mapped[List['OnboardingStep']] = so.relationship( 299 'OnboardingStep', 300 back_populates = 'training_module', 301 cascade = 'all, delete-orphan' 302 ) 303 304 def __repr__(self): 305 """Returns a string representation of the TrainingModule object.""" 306 return f'<TrainingModule {self.module_title}>'
Represents a training module in the system.
Attributes:
- id (int): Primary key.
- module_title (str): Title of the module.
- module_description (str): Detailed description.
- module_instructions (str): Instructions for completing the module.
- video_url (Optional[str]): Optional URL for video content.
- active (bool): Indicates whether the module is currently active.
- questions (list[Question]): Questions associated with the module.
- user_progress (list[UserModuleProgress]): Progress entries for users.
- onboarding_steps (List[OnboardingStep]): Steps in assigned onboarding paths.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
309class Question (db.Model): 310 """Represents a question in the system. 311 312 Attributes: 313 id (int): Primary key. 314 question_text (str): The text of the question. 315 training_module_id (int): Foreign key to TrainingModule. 316 training_module (TrainingModule): Associated training module. 317 options (list[Option]): List of answer choices for this question. 318 """ 319 __tablename__ = 'question' 320 321 # Primary key 322 id: so.Mapped[int] = so.mapped_column(primary_key=True) 323 324 # Question details 325 question_text: so.Mapped[str] = so.mapped_column( 326 sa.String(1000), 327 nullable=False 328 ) 329 330 # Relationship with training module id 331 training_module_id: so.Mapped[int] = so.mapped_column( 332 sa.ForeignKey('training_module.id'), 333 nullable=False 334 ) 335 training_module: so.Mapped['TrainingModule'] = so.relationship( 336 'TrainingModule', 337 back_populates = 'questions') 338 339 # Relationship with options 340 options: so.Mapped[List['Option']] = so.relationship( 341 'Option', 342 back_populates = 'question', 343 cascade='all, delete-orphan' 344 ) 345 346 def __repr__(self): 347 """Returns a string representation of the Question object.""" 348 return f'<Question {self.question_text}>'
Represents a question in the system.
Attributes:
- id (int): Primary key.
- question_text (str): The text of the question.
- training_module_id (int): Foreign key to TrainingModule.
- training_module (TrainingModule): Associated training module.
- options (list[Option]): List of answer choices for this question.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
351class Option (db.Model): 352 """Represents answer options for a question. 353 354 Attributes: 355 id (int): Primary key. 356 question_id (int): Foreign key to the question. 357 option_text (str): The text of this option. 358 is_correct (bool): True if this option is the correct answer. 359 question (Question): The associated question. 360 """ 361 __tablename__ = "option" 362 363 # Primary key 364 id: so.Mapped[int] = so.mapped_column(primary_key=True) 365 366 # Option details 367 question_id: so.Mapped[int] = so.mapped_column( 368 sa.ForeignKey('question.id'), 369 nullable=False 370 ) 371 option_text: so.Mapped[str] = so.mapped_column( 372 sa.String(500), 373 nullable=False 374 ) 375 is_correct: so.Mapped[bool] = so.mapped_column( 376 sa.Boolean, 377 default=False, 378 nullable=False 379 ) 380 381 # Relationship with question 382 question: so.Mapped['Question'] = so.relationship( 383 'Question', 384 back_populates = 'options' 385 ) 386 387 def __repr__(self): 388 """Returns a string representation of the Option object.""" 389 return f'<Option {self.option_text}>'
Represents answer options for a question.
Attributes:
- id (int): Primary key.
- question_id (int): Foreign key to the question.
- option_text (str): The text of this option.
- is_correct (bool): True if this option is the correct answer.
- question (Question): The associated question.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
392class UserModuleProgress (db.Model): 393 """ 394 Represents the progress of a user in a training module. 395 396 Attributes: 397 id (int): Primary key. 398 start_date (datetime): When the module was started. 399 completed_date (datetime, optional): When the module was completed. 400 score (int, optional): The score achieved by the user in the module. 401 attempts (int): Number of attempts made by the user. 402 user_id (int): Foreign key to the User model. 403 user (User): The user associated with this progress entry. 404 training_module_id (int): Foreign key to the TrainingModule model. 405 training_module (TrainingModule): The training module associated with 406 this progress entry. 407 answers (list[UserQuestionAnswer]): Answers submitted during this attempt. 408 """ 409 __tablename__ = 'user_module_progress' 410 411 # Primary key 412 id: so.Mapped[int] = so.mapped_column(primary_key=True) 413 414 # User Module Progress details 415 start_date: so.Mapped[datetime] = so.mapped_column( 416 sa.DateTime, 417 default = lambda: datetime.now(timezone.utc), 418 nullable = False 419 ) 420 completed_date: so.Mapped[datetime] = so.mapped_column( 421 sa.DateTime, 422 nullable = True 423 ) 424 score: so.Mapped[int] = so.mapped_column( 425 sa.Integer, 426 nullable = True 427 ) 428 attempts: so.Mapped[int] = so.mapped_column( 429 sa.Integer, 430 default=0, 431 nullable = False 432 ) 433 434 # Relationship to User 435 user_id: so.Mapped[int] = so.mapped_column( 436 sa.ForeignKey('user.id'), 437 nullable = False 438 ) 439 user: so.Mapped['User'] = so.relationship( 440 'User', 441 back_populates = 'module_progress' 442 ) 443 444 # Relationship to Training Module 445 training_module_id: so.Mapped[int] = so.mapped_column( 446 sa.ForeignKey('training_module.id'), 447 nullable = False 448 ) 449 training_module: so.Mapped['TrainingModule'] = so.relationship( 450 'TrainingModule', 451 back_populates = 'user_progress' 452 ) 453 454 # Relationship to User Question Answer 455 answers: so.Mapped[List['UserQuestionAnswer']] = so.relationship( 456 'UserQuestionAnswer', 457 back_populates = 'progress', 458 cascade = 'all, delete-orphan' 459 )
Represents the progress of a user in a training module.
Attributes:
- id (int): Primary key.
- start_date (datetime): When the module was started.
- completed_date (datetime, optional): When the module was completed.
- score (int, optional): The score achieved by the user in the module.
- attempts (int): Number of attempts made by the user.
- user_id (int): Foreign key to the User model.
- user (User): The user associated with this progress entry.
- training_module_id (int): Foreign key to the TrainingModule model.
- training_module (TrainingModule): The training module associated with this progress entry.
- answers (list[UserQuestionAnswer]): Answers submitted during this attempt.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
462class UserQuestionAnswer (db.Model): 463 """Represents an answer submitted by a user to a specific question. 464 465 Attributes: 466 id (int): Primary key. 467 is_correct (bool): True if the selected option was correct. 468 progress_id (int): Foreign key to the UserModuleProgress model. 469 progress (UserModuleProgress): Relationship to the user's progress 470 record. 471 question_id (int): Foreign key to the Question. 472 question (Question): Question associated with this answer. 473 selected_option_id (int, optional): Foreign key to the chosen Option. 474 selected_option (Option, optional): Relationship to the selected 475 Option (if any). 476 """ 477 __tablename__ = 'user_question_answer' 478 479 # Primary key 480 id: so.Mapped[int] = so.mapped_column(primary_key=True) 481 is_correct: so.Mapped[bool] = so.mapped_column(sa.Boolean) 482 483 # User Question Answer details 484 progress_id: so.Mapped[int] = so.mapped_column( 485 sa.ForeignKey('user_module_progress.id'), 486 nullable = False 487 ) 488 489 # Relationship to User Module Progress 490 progress: so.Mapped['UserModuleProgress'] = so.relationship( 491 'UserModuleProgress', 492 back_populates = 'answers' 493 ) 494 495 # Relationship to question 496 question_id: so.Mapped[int] = so.mapped_column( 497 sa.ForeignKey('question.id'), 498 nullable = False 499 ) 500 question: so.Mapped['Question'] = so.relationship('Question') 501 502 # Relationship to option 503 selected_option_id: so.Mapped[int] = so.mapped_column( 504 sa.ForeignKey('option.id'), 505 nullable = True 506 ) 507 selected_option: so.Mapped['Option'] = so.relationship('Option')
Represents an answer submitted by a user to a specific question.
Attributes:
- id (int): Primary key.
- is_correct (bool): True if the selected option was correct.
- progress_id (int): Foreign key to the UserModuleProgress model.
- progress (UserModuleProgress): Relationship to the user's progress record.
- question_id (int): Foreign key to the Question.
- question (Question): Question associated with this answer.
- selected_option_id (int, optional): Foreign key to the chosen Option.
- selected_option (Option, optional): Relationship to the selected Option (if any).
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
510class OnboardingPath(db.Model): 511 """Represents an onboarding path defining a sequence of steps for staff. 512 513 Attributes: 514 id (int): Primary key. 515 path_name (str): Name of the onboarding path (e.g., “office”, 516 “operational”). 517 steps (list[OnboardingStep]): Ordered steps in this path. 518 """ 519 __tablename__ = 'onboarding_path' 520 521 # Primary key 522 id: so.Mapped[int] = so.mapped_column(primary_key=True) 523 524 #Onboarding path details 525 path_name: so.Mapped[str] = so.mapped_column( 526 sa.String(100), 527 nullable=False, 528 unique=True 529 ) 530 531 # Relationship with onboarding steps 532 steps: so.Mapped[List['OnboardingStep']] = so.relationship( 533 'OnboardingStep', 534 back_populates='path', 535 cascade='all, delete-orphan' 536 ) 537 538 def __repr__(self): 539 """Returns a string representation of the Onboarding Path object.""" 540 return f"<OnboardingPath {self.path_name}>"
Represents an onboarding path defining a sequence of steps for staff.
Attributes:
- id (int): Primary key.
- path_name (str): Name of the onboarding path (e.g., “office”, “operational”).
- steps (list[OnboardingStep]): Ordered steps in this path.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
543class OnboardingStep(db.Model): 544 """Step within an onboarding path, e.g. a training module or task. 545 546 Attributes: 547 id (int): Primary key. 548 step_name (str): Name of this step. 549 onboarding_path_id (int): Foreign key to the OnboardingPath. 550 path (OnboardingPath): Relationship back to the parent path. 551 training_module_id (int, optional): Foreign key to the TrainingModule, 552 if any. 553 training_module (TrainingModule): The training module associated with 554 this step. 555 """ 556 __tablename__ = 'onboarding_step' 557 558 # Primary key 559 id: so.Mapped[int] = so.mapped_column(primary_key = True) 560 561 # Onboarding Step details 562 step_name: so.Mapped[str] = so.mapped_column( 563 sa.String(150), 564 nullable = False 565 ) 566 567 # Relationship to Onboarding Path 568 onboarding_path_id: so.Mapped[int] = so.mapped_column( 569 sa.ForeignKey('onboarding_path.id'), 570 nullable = False 571 ) 572 path: so.Mapped['OnboardingPath'] = so.relationship( 573 'OnboardingPath', 574 back_populates = 'steps' 575 ) 576 577 # Relationship to training modules 578 training_module_id: so.Mapped[int] = so.mapped_column( 579 sa.ForeignKey('training_module.id'), 580 nullable = True 581 ) 582 training_module: so.Mapped['TrainingModule'] = so.relationship( 583 'TrainingModule', 584 back_populates = 'onboarding_steps' 585 ) 586 587 def __repr__(self): 588 """Returns a string representation of the OnboardingStep object.""" 589 return f"<OnboardingStep {self.step_name}>"
Step within an onboarding path, e.g. a training module or task.
Attributes:
- id (int): Primary key.
- step_name (str): Name of this step.
- onboarding_path_id (int): Foreign key to the OnboardingPath.
- path (OnboardingPath): Relationship back to the parent path.
- training_module_id (int, optional): Foreign key to the TrainingModule, if any.
- training_module (TrainingModule): The training module associated with this step.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
592class DocumentRepository(db.Model): 593 """Represents a document in the repository. 594 595 Attributes: 596 id (int): Primary key. 597 document_title (str): Title of the document. 598 document_category (str): Category of the document (e.g., Policy, Guide, 599 Form). 600 upload_date (datetime): Timestamp when uploaded. 601 file_path (str): Filesystem path to the uploaded file. 602 user_id (int): Foreign key to the uploaders User model. 603 uploaded_by_user (User): The user who uploaded the document. 604 """ 605 __tablename__ = 'document_repository' 606 607 # Primary key 608 id: so.Mapped[int] = so.mapped_column(primary_key=True) 609 610 # Repository details 611 document_title: so.Mapped[str] = so.mapped_column( 612 sa.String(150), 613 nullable = False 614 ) 615 document_category: so.Mapped[str] = so.mapped_column( 616 sa.Enum('Policy', 'Guide', 'Form', 617 name = 'document_category'), 618 nullable = False 619 ) 620 upload_date: so.Mapped[datetime] = so.mapped_column( 621 sa.DateTime, 622 default=lambda: datetime.now(timezone.utc), 623 nullable = False 624 ) 625 file_path: so.Mapped[str] = so.mapped_column( 626 sa.String(300), 627 nullable = False 628 ) 629 630 # Relationship to User 631 user_id: so.Mapped[int] = so.mapped_column( 632 sa.ForeignKey('user.id'), 633 nullable = False 634 ) 635 uploaded_by_user: so.Mapped['User'] = so.relationship('User') 636 637 def __repr__(self): 638 """Returns a string representation of the Document Repository object.""" 639 return f"<DocumentRepository {self.document_title}>"
Represents a document in the repository.
Attributes:
- id (int): Primary key.
- document_title (str): Title of the document.
- document_category (str): Category of the document (e.g., Policy, Guide, Form).
- upload_date (datetime): Timestamp when uploaded.
- file_path (str): Filesystem path to the uploaded file.
- user_id (int): Foreign key to the uploaders User model.
- uploaded_by_user (User): The user who uploaded the document.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
642class Report(db.Model): 643 """Represents a report in the system. 644 645 Attributes: 646 id (int): Primary key. 647 report_type (str): Type of report (e.g., Completion, Performance). 648 description (str): Short description of the report. 649 report_data (str, optional): Stored Json report content. 650 created_at (datetime): Timestamp when the report was created. 651 """ 652 __tablename__ = 'report' 653 654 # Primary key 655 id: so.Mapped[int] = so.mapped_column(primary_key=True) 656 657 # Report details 658 report_type: so.Mapped[str] = so.mapped_column( 659 sa.Enum('Completion', 'Performance', name = 'report_type'), 660 nullable = False 661 ) 662 description: so.Mapped[str] = so.mapped_column( 663 sa.String(255), 664 nullable = False 665 ) 666 report_data: so.Mapped[Optional[str]] = so.mapped_column( 667 sa.Text, 668 nullable = True) 669 created_at: so.Mapped[datetime] = so.mapped_column( 670 sa.DateTime, 671 default = lambda: datetime.now(timezone.utc), 672 nullable = False 673 ) 674 675 def __repr__(self): 676 """Returns a string representation of the Report object.""" 677 return f"<Report {self.report_type} created on {self.created_at}>"
Represents a report in the system.
Attributes:
- id (int): Primary key.
- report_type (str): Type of report (e.g., Completion, Performance).
- description (str): Short description of the report.
- report_data (str, optional): Stored Json report content.
- created_at (datetime): Timestamp when the report was created.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.