diff --git a/.gitignore b/.gitignore index 00702c49..883a9a89 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,8 @@ __pycache__/ instance/test.db # Ignore VS Code settings (optional) -#.vscode/ +.vscode/ # Ignore environment files (optional) -.env \ No newline at end of file +.env +venv/ diff --git a/App/controllers/__init__.py b/App/controllers/__init__.py index b3278c01..c61bfd15 100644 --- a/App/controllers/__init__.py +++ b/App/controllers/__init__.py @@ -1,5 +1,8 @@ -from .user import * +from .user import create_user, login, set_password, check_password from .auth import * from .initialize import * from .position import * from .shortlist import * +from .employer import * +from .student import * +from .staff import * diff --git a/App/controllers/employer.py b/App/controllers/employer.py new file mode 100644 index 00000000..64266a03 --- /dev/null +++ b/App/controllers/employer.py @@ -0,0 +1,57 @@ +from App.models.employer import Employer +from App.database import db +from App.models.shortlist import Shortlist +from App.models.position import Position +from App.models.position import PositionStatus +from App.models.shortlist import DecisionStatus + +def createPosition(title, employerID, description,numberOfPositions): + employer = Employer.query.filter_by(employerID = employerID).first() + if not employer: + return None + position = Position(employerID = employerID, title = title , description = description, numberOfPositions = numberOfPositions) + db.session.add(position) + db.session.commit() + +def viewApplicants(positionID): + position = Position.query.filter_by(positionID = positionID).first() + applicants = position.shortlist if position else [] + + return applicants + + +def makeDecision(shortlistID, status ): + shortlist = Shortlist.query.filter_by(shortlistID = shortlistID).first() + if shortlist and status in ["Accepted", "Rejected", "Pending"]: + shortlist.status = DecisionStatus(status.lower()) + db.session.commit() + +def editPosition( employerID, positionID, title, description, numberOfPositions, shortlistID): + position = Position.query.get(positionID) + shortlist = Shortlist.query.get(shortlistID) + if not position or position.employerID != employerID: + return None + if not shortlist: + return None + + + + if title: + position.title = title + if description: + position.description = description + if numberOfPositions: + position.numberOfPositions = numberOfPositions + + allShortlist = Shortlist.query.filter_by(positonID = positionID).all() + + accepted = sum( 1 for s in allShortlist if s.status == DecisionStatus.accepted) + + if accepted >= position.numberOfPositions: + position.status = PositionStatus.closed + else: + position.status = PositionStatus.open + + + db.session.commit() + return position diff --git a/App/controllers/initialize.py b/App/controllers/initialize.py index 88c893bd..65e98b6a 100644 --- a/App/controllers/initialize.py +++ b/App/controllers/initialize.py @@ -1,6 +1,6 @@ from .user import create_user -from .shortlist import add_student_to_shortlist -from .position import open_position +from .staff import addToshortlist +from .employer import createPosition from App.database import db @@ -10,6 +10,7 @@ def initialize(): create_user('bob', 'bobpass', "student") create_user('frank', 'frankpass', "employer") create_user('john', 'johnpass', "staff") - open_position(user_id=2, title='Software Engineer', number_of_positions= 6) - open_position(user_id=2, title='Mechanical Engineer', number_of_positions= 6) - add_student_to_shortlist(student_id=1, position_id=1, staff_id=3) + createPosition( title='Software Engineer', employerID = 2, description = ' ', positionID = 4 , number_of_positions= 6) + createPosition( title='Web Designer', employerID = 2, description = ' ', positionID = 5 , number_of_positions= 6) + + addToshortlist(1, 1, 3) diff --git a/App/controllers/position.py b/App/controllers/position.py index 005bce4d..1fb2a428 100644 --- a/App/controllers/position.py +++ b/App/controllers/position.py @@ -1,34 +1,22 @@ from App.models import Position, Employer from App.database import db -def open_position(user_id, title, number_of_positions=1): - employer = Employer.query.filter_by(user_id=user_id).first() + +def getPositionsByEmployer(employerID): + employer = Employer.query.filter_by(employerID = employerID).first() if not employer: - return None + return [] - new_position = Position(title=title, number=number_of_positions, employer_id=employer.id) - db.session.add(new_position) - try: - db.session.commit() - return new_position - except Exception as e: - db.session.rollback() - return None - + return Position.query.filter_by(employerID = employerID).all() -def get_positions_by_employer(user_id): - employer = Employer.query.filter_by(user_id=user_id).first() - return db.session.query(Position).filter_by(employer_id=employer.id).all() +def getAllPositions_json(): + positions = Position.query.all() + return [p.toJSON() for p in positions] if positions else[] -def get_all_positions_json(): - positions = Position.query.all() - if positions: - return [position.toJSON() for position in positions] - return [] -def get_positions_by_employer_json(user_id): - employer = Employer.query.filter_by(user_id=user_id).first() - positions = db.session.query(Position).filter_by(employer_id=employer.id).all() - if positions: - return [position.toJSON() for position in positions] - return [] \ No newline at end of file +def getPositionsByEmployer_json(employerID): + employer = Employer.query.filter_by(employerID = employerID).first() + if not employer: + return [] + positions = Position.query.filter_by(employerID = employerID).all() + return[p.toJSON() for p in positions] if positions else [] \ No newline at end of file diff --git a/App/controllers/shortlist.py b/App/controllers/shortlist.py index b9fa3844..d02f8a3d 100644 --- a/App/controllers/shortlist.py +++ b/App/controllers/shortlist.py @@ -1,40 +1,36 @@ -from sqlalchemy import false -from App.models import Shortlist, Position, Staff, Student + +from App.models import Shortlist, Position, DecisionStatus, Student from App.database import db -def add_student_to_shortlist(student_id, position_id, staff_id): - teacher = db.session.query(Staff).filter_by(user_id=staff_id).first() - student = db.session.query(Student).filter_by(user_id=student_id).first() - if student == None or teacher == None: - return False - list = db.session.query(Shortlist).filter_by(student_id=student.id, position_id=position_id).first() - position = db.session.query(Position).filter( - Position.id == position_id, - Position.number_of_positions > 0, - Position.status == "open" - ).first() - if teacher and not list and position: - shortlist = Shortlist(student_id=student.id, position_id=position.id, staff_id=teacher.id, title=position.title) - db.session.add(shortlist) - db.session.commit() - return shortlist - - return False -def decide_shortlist(student_id, position_id, decision): - student = db.session.query(Student).filter_by(user_id=student_id).first() - shortlist = db.session.query(Shortlist).filter_by(student_id=student.id, position_id=position_id, status ="pending").first() - position = db.session.query(Position).filter(Position.id==position_id, Position.number_of_positions > 0).first() - if shortlist and position: - shortlist.update_status(decision) - position.update_number_of_positions(position.number_of_positions - 1) - return shortlist - return False +def shortlistedStudent(studentID): + student = Student.query.filter_by(studentID = studentID).first() + if not student: + return[ ] + return Shortlist.query.filter_by(studentID =studentID).all() -def get_shortlist_by_student(student_id): - student = db.session.query(Student).filter_by(user_id=student_id).first() - return db.session.query(Shortlist).filter_by(student_id=student.id).all() +def shortlistedByPosition(positionID): + return Shortlist.query.filter_by(positionID = positionID).all() -def get_shortlist_by_position(position_id): - return db.session.query(Shortlist).filter_by(position_id=position_id).all() + +def decideShortlist(studentID, positionID, decision): + student = Student.query.filter_by(studentID = studentID).first() + if not student: + return False + + shortlist = Shortlist.query.filter_by(studentID= studentID, positionID = positionID,status = DecisionStatus.pending ).first() + if not shortlist: + return False + + position = Position.query.filter_by(positionID = positionID).first() + if not position or position.numberOfPositions <= 0: + return False + + + shortlist.update_status(decision) + + if decision == "accepted": + position.update_number_of_positions(position.numberOfPositions -1) + + return shortlist \ No newline at end of file diff --git a/App/controllers/staff.py b/App/controllers/staff.py new file mode 100644 index 00000000..8d38b2dc --- /dev/null +++ b/App/controllers/staff.py @@ -0,0 +1,19 @@ +from App.database import db +from App.models.shortlist import Shortlist +from App.models.student import Student +from App.models.position import Position + +def addToshortlist(positionID, studentID ): + exists = Shortlist.query.filter_by(positionID = positionID, studentID= studentID).first() + if exists: + return f"Student{studentID} is already shortlisted for position {positionID}" + shortlist = Shortlist(positionID = positionID, studentID= studentID) + db.session.add(shortlist) + db.session.commit() + +def viewAvailablePositions(): + return Position.query.all() + + + + diff --git a/App/controllers/state.py b/App/controllers/state.py new file mode 100644 index 00000000..a06a18f4 --- /dev/null +++ b/App/controllers/state.py @@ -0,0 +1,36 @@ +from App.database import db +from .states.accepted import Accepted +from states.rejected import Rejected +from .states.shortlisted import Shortlisted +from .states.applied import Applied +from .student import Student + + +STATUS_MAP = { + "Applied": Applied, + "Shortlisted": Shortlisted, + "Accepted": Accepted, + "Rejected": Rejected + } + + +class StudentController: + + + + @staticmethod + def updateStatus(studentID, newStatus): + + if newStatus not in STATUS_MAP: + return {"error": "Invalid status"} + + student = Student.query.filter_by(studentID = studentID).first() + if not student: + return {"error": "Student not found"} + + student.status = newStatus + + StateClass = STATUS_MAP[newStatus] + student.state = StateClass(student) + + db.session.commit() diff --git a/App/controllers/student.py b/App/controllers/student.py new file mode 100644 index 00000000..544ef4b6 --- /dev/null +++ b/App/controllers/student.py @@ -0,0 +1,47 @@ +from App.database import db +from App.models.student import Student +from App.models.shortlist import Shortlist +from App.models.states import Accepted, Rejected, Applied, Shortlisted + + +def viewShortlist(studentID): + student = Student.query.filter_by(studentID=studentID).first() + entries = student.shortlist if student else [] + + return{ + "studentID" : studentID, + "shortlist": [ + { + "shortlistID" : s.shortlistID, + "positionID": s.positionID, + "status": s.status.value} + for s in entries] + + + } + +def updateStatus(studentID, state): + student = Student.query.filter_by(studentID = studentID).first() + + if not student: + return None + + if student and state: + + mapping = { + "Accepted": Accepted, + "Rejected": Rejected, + "Shortlisted": Shortlisted, + "Applied" : Applied + } + + if state in mapping: + student.changeStatus(mapping[state]) + + + db.session.commit() + + +def viewEmployerDecision( studentID): + return Shortlist.query.filter_by(studentID = studentID).all() + diff --git a/App/controllers/user.py b/App/controllers/user.py index bd677795..8eb7cd4a 100644 --- a/App/controllers/user.py +++ b/App/controllers/user.py @@ -1,53 +1,30 @@ from App.models import User, Student, Employer, Staff from App.database import db -def create_user(username, password, user_type): - try: - newuser = User(username=username, password=password, role=user_type) - db.session.add(newuser) - db.session.flush() - - if user_type == "student": - student = Student(username=username, user_id=newuser.id) - db.session.add(student) - elif user_type == "employer": - employer = Employer(username=username, user_id=newuser.id) - db.session.add(employer) - elif user_type == "staff": - staff = Staff(username=username, user_id=newuser.id) - db.session.add(staff) - else: - return False - - db.session.commit() - return True - except Exception as e: - db.session.rollback() - return False - +def create_user(username, password , role = "user"): + newUser = User (username=username, password = password) + newUser.Role = role + db.session.add(newUser) + db.session.commit() + return newUser -def get_user_by_username(username): - result = db.session.execute(db.select(User).filter_by(username=username)) - return result.scalar_one_or_none() +def login( username, password): + user = User.query.filter_by(username =username).first() + if user and user.check_password(password): + return user + return None -def get_user(id): - return db.session.get(User, id) - -def get_all_users(): - return db.session.scalars(db.select(User)).all() +def check_password( userID, password): + user= User.query.get(userID) + if not user: + return False + return user.check_password(password) -def get_all_users_json(): - users = get_all_users() - if not users: - return [] - users = [user.get_json() for user in users] - return users +def set_password( userID, newPassword): + user = User.query.get(userID) + if not user: + return None + user.set_password(newPassword) + db.session.commit() + return user -def update_user(id, username): - user = get_user(id) - if user: - user.username = username - # user is already in the session; no need to re-add - db.session.commit() - return True - return None diff --git a/App/models/employer.py b/App/models/employer.py index 750b7922..fe74af5f 100644 --- a/App/models/employer.py +++ b/App/models/employer.py @@ -1,13 +1,20 @@ from App.database import db -from App.models.user import User +from .user import User -class Employer(db.Model): +class Employer(User): __tablename__ = 'employer' - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=True) - username = db.Column(db.String(20), nullable=False, unique=True) - positions = db.relationship("Position", back_populates="employer") - - def __init__(self, username, user_id): - self.username = username - self.user_id = user_id \ No newline at end of file + + employerID = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + name = db.Column(db.String(100), nullable=False) + company = db.Column(db.String(256), nullable=False) + + positions = db.relationship("Position", back_populates="createdBy", lazy=True, cascade="all, delete-orphan") + + __mapper_args__ = { + 'polymorphic_identity': 'employer' + } + + def __init__(self, username, password, name, company): + super().__init__(username, password) + self.name = name + self.company = company \ No newline at end of file diff --git a/App/models/position.py b/App/models/position.py index 58d120a9..78e808e9 100644 --- a/App/models/position.py +++ b/App/models/position.py @@ -3,34 +3,37 @@ import enum class PositionStatus(enum.Enum): - open = "open" - closed = "closed" + open = "Open" + closed = "Closed" class Position(db.Model): __tablename__ = 'position' - id = db.Column(db.Integer, primary_key=True) - title = db.Column(db.String(255), nullable=False) - number_of_positions = db.Column(db.Integer, default=1) + + positionID = db.Column(db.Integer, primary_key=True) + employerID = db.Column(db.Integer, db.ForeignKey('employer.employerID'), nullable=False) + title = db.Column(db.String(256), nullable=False) + description = db.Column(db.String(256), nullable=False) + numberOfPositions = db.Column(db.Integer, nullable=False) status = db.Column(Enum(PositionStatus, native_enum=False), nullable=False, default=PositionStatus.open) - employer_id = db.Column(db.Integer, db.ForeignKey('employer.id'), nullable=False) - employer = db.relationship("Employer", back_populates="positions") - def __init__(self, title, employer_id, number): + createdBy = db.relationship("Employer", back_populates="positions", lazy=True) + shortlist = db.relationship("Shortlist", back_populates="position", lazy=True, cascade="all, delete-orphan") + + def __init__(self, employer, title, description, numPositions): + self.createdBy = employer self.title = title - self.employer_id = employer_id - self.status = "open" - self.number_of_positions = number - + self.description = description + self.numberOfPositions = numPositions def update_status(self, status): - self.status = status + self.status = PositionStatus(status) db.session.commit() return self.status def update_number_of_positions(self, number_of_positions): - self.number_of_positions = number_of_positions + self.numberOfPositions = number_of_positions db.session.commit() - return self.number_of_positions + return self.numberOfPositions def delete_position(self): db.session.delete(self) @@ -42,9 +45,9 @@ def list_positions(self): def toJSON(self): return { - "id": self.id, + "id": self.positionID, "title": self.title, - "number_of_positions": self.number_of_positions, + "number_of_positions": self.numberOfPositions, "status": self.status.value, - "employer_id": self.employer_id + "employer_id": self.employerID } \ No newline at end of file diff --git a/App/models/shortlist.py b/App/models/shortlist.py index 3d16ea8f..c4ebee96 100644 --- a/App/models/shortlist.py +++ b/App/models/shortlist.py @@ -1,50 +1,51 @@ from App.database import db -from App.models.user import User +from .user import User from sqlalchemy import Enum import enum class DecisionStatus(enum.Enum): - accepted = "accepted" - rejected = "rejected" - pending = "pending" + accepted = "Accepted" + rejected = "Rejected" + pending = "Pending" class Shortlist(db.Model): __tablename__ = 'shortlist' - id = db.Column(db.Integer, primary_key=True) - student_id = db.Column(db.Integer, db.ForeignKey('student.id'), nullable=False) - title = db.Column(db.String(512), nullable=False) - position_id = db.Column(db.Integer, db.ForeignKey('position.id')) - staff_id = db.Column(db.Integer, db.ForeignKey('staff.id'), nullable=False) + + shortlistID = db.Column(db.Integer, primary_key=True) + positionID = db.Column(db.Integer, db.ForeignKey('position.positionID')) + studentID = db.Column(db.Integer, db.ForeignKey('student.studentID'), nullable=False) + staffID = db.Column(db.Integer, db.ForeignKey('staff.staffID'), nullable=False) status = db.Column(Enum(DecisionStatus, native_enum=False), nullable=False, default=DecisionStatus.pending) - student = db.relationship('Student', backref=db.backref('shortlist', lazy=True)) - position = db.relationship('Position', backref=db.backref('shortlist', lazy=True)) - staff = db.relationship('Staff', backref=db.backref('shortlist', lazy=True)) - - def __init__(self, student_id, position_id, staff_id, title): - self.student_id = student_id - self.position_id = position_id - self.status = "pending" - self.staff_id = staff_id - self.title = title + + staff = db.relationship('Staff', back_populates='shortlist', lazy=True) + student = db.relationship('Student', back_populates='shortlist', lazy=True) + position = db.relationship('Position', back_populates='shortlist', lazy=True) + + def __init__(self, positionID, studentID, staffID): + self.positionID = positionID + self.studentID = studentID + self.staffID = staffID def update_status(self, status): - self.status = PositionStatus(status) + self.status = DecisionStatus(status) db.session.commit() return self.status - def student_shortlist(self, student_id): - return db.session.query(Shortlist).filter_by(student_id=student_id).all() + # These two commented out methods should be added to the shortlist controller + + # def student_shortlist(self, student_id): + # return db.session.query(Shortlist).filter_by(student_id=student_id).all() - def position_shortlist(self, position_id): - return db.session.query(Shortlist).filter_by(position_id=position_id).all() + # def position_shortlist(self, position_id): + # return db.session.query(Shortlist).filter_by(position_id=position_id).all() def toJSON(self): return{ - "id": self.id, + "id": self.shortlistID, "title": self.title, - "student_id": self.student_id, - "position_id": self.position_id, - "staff_id": self.staff_id, + "student_id": self.studentID, + "position_id": self.positionID, + "staff_id": self.staffID, "status": self.status.value } \ No newline at end of file diff --git a/App/models/staff.py b/App/models/staff.py index c5e7441d..f598185f 100644 --- a/App/models/staff.py +++ b/App/models/staff.py @@ -1,19 +1,29 @@ from App.database import db -from App.models.user import User +from .user import User from App.models.shortlist import Shortlist -class Staff(db.Model): +class Staff(User): __tablename__ = 'staff' - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=True) - username = db.Column(db.String(20), nullable=False, unique=True) - def __init__(self, username, user_id): - self.username = username - self.user_id = user_id + staffID = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + name = db.Column(db.String(100), nullable=False) + faculty = db.Column(db.String(256), nullable=False) - def add_to_shortlist(self, student_id, position_id): - shortlist = Shortlist(student_id=student_id, position_id=position_id, staff_id=self.id) - db.session.add(shortlist) - db.session.commit() - return shortlist \ No newline at end of file + shortlist = db.relationship("Shortlist", back_populates="staff", lazy=True, cascade="all, delete-orphan") + + __mapper_args__ = { + 'polymorphic_identity': 'staff' + } + + def __init__(self, username, password, name, faculty): + super().__init__(username, password) + self.name = name + self.faculty = faculty + + # This method should be added to the staff controller + + # def add_to_shortlist(self, student_id, position_id): + # shortlist = Shortlist(student_id=student_id, position_id=position_id, staff_id=self.id) + # db.session.add(shortlist) + # db.session.commit() + # return shortlist \ No newline at end of file diff --git a/App/models/states.py b/App/models/states.py new file mode 100644 index 00000000..6fbb7249 --- /dev/null +++ b/App/models/states.py @@ -0,0 +1,51 @@ +from abc import ABC, abstractmethod + +# State Interface +class ApplicationStatus(ABC): + def __init__(self, student): + # Reference to the student context + self.student = student + + @abstractmethod + def viewShortlist(self): + pass + + @abstractmethod + def viewEmployerDecision(self): + pass + + +# Accepted State +class Accepted(ApplicationStatus): + def viewShortlist(self): + return + + def viewEmployerDecision(self): + return + + +# Rejected State +class Rejected(ApplicationStatus): + def viewShortlist(self): + return + + def viewEmployerDecision(self): + return + + +# Shortlisted State +class Shortlisted(ApplicationStatus): + def viewShortlist(self): + return + + def viewEmployerDecision(self): + return + + +# Applied State +class Applied(ApplicationStatus): + def viewShortlist(self): + return + + def viewEmployerDecision(self): + return \ No newline at end of file diff --git a/App/models/student.py b/App/models/student.py index f13e9248..fe2bef0e 100644 --- a/App/models/student.py +++ b/App/models/student.py @@ -1,34 +1,41 @@ from App.database import db -from App.models.user import User -from sqlalchemy.ext.hybrid import hybrid_property -from datetime import date +from .user import User +from App.models.states import Accepted, Rejected, Shortlisted, Applied -class Student(db.Model): +class Student(User): __tablename__ = 'student' - id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False, unique=True) - username = db.Column(db.String(20), nullable=False, unique=True) - email = db.Column(db.String(256)) - dob = db.Column(db.Date) - gender = db.Column(db.String(256)) - degree = db.Column(db.String(256)) - phone = db.Column(db.String(256)) - gpa = db.Column(db.Float) - resume = db.Column(db.String(256)) + + studentID = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + name = db.Column(db.String(100), nullable=False) + degree = db.Column(db.String(256), nullable=False) + resume = db.Column(db.String(256), nullable=False) + GPA = db.Column(db.Float, nullable=False) - def __init__(self, username, user_id): - self.username = username - self.user_id = user_id + # Reference to applicant state + # Default state is Applied. This refers to a student who has applied to the intersnship programme + status = None -# def update_DOB(self, date): -# self.DOB = date -# db.session.commit() -# return self.DOB -# -# @hybrid_property -# def age(self): -# if self.DOB is None: -# return None -# today = date.today() -# dob = self.DOB -# return today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day)) \ No newline at end of file + shortlist = db.relationship("Shortlist", back_populates="student", lazy=True, cascade="all, delete-orphan") + + __mapper_args__ = { + 'polymorphic_identity': 'student' + } + + def __init__(self, username, password, name, degree, resume, GPA): + super().__init__(username, password) + self.name = name + self.degree = degree + self.resume = resume + self.GPA = GPA + self.changeStatus(Applied) + + def viewShortlist(self): + self.status.viewShortlist() + + def viewEmployerDecision(self): + self.status.viewEmployerDecision() + + def changeStatus(self, nextStatus): + self.status = nextStatus(self) + db.session.add(self) + db.session.commit() \ No newline at end of file diff --git a/App/models/user.py b/App/models/user.py index bf9b021b..e3edc2ce 100644 --- a/App/models/user.py +++ b/App/models/user.py @@ -3,25 +3,31 @@ class User(db.Model): __tablename__ = 'user' + id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), nullable=False, unique=True) password = db.Column(db.String(256), nullable=False) role = db.Column(db.String(50), nullable=False) - student = db.relationship('Student', backref='user', uselist=False) - employer = db.relationship('Employer', backref='user', uselist=False) - staff = db.relationship('Staff', backref='user', uselist=False) + __mapper_args__ = { + 'polymorphic_identity': 'user', + 'polymorphic_on': 'role' + } + + # Remember to remove instances where these relationships were used: + + # student = db.relationship('Student', backref='user', uselist=False) + # employer = db.relationship('Employer', backref='user', uselist=False) + # staff = db.relationship('Staff', backref='user', uselist=False) + + # This implementation uses joined-table inheritance. + # Although all user types are treated as a single logical entity (User) in Python, SQLAlchemy creates a separate table for each subclass (e.g., student). + # Each subclass table contains only the fields specific to that subtype and uses a primary key that is also a foreign key referencing the user table. + # SQLAlchemy then performs joins between the base and child tables when loading subclass objects. - def __init__(self, username, password, role): + def __init__(self, username, password): self.username = username self.set_password(password) - self.role = role - - def get_json(self): - return{ - 'id': self.id, - 'username': self.username - } def set_password(self, password): """Create hashed password.""" @@ -30,5 +36,10 @@ def set_password(self, password): def check_password(self, password): """Check hashed password.""" return check_password_hash(self.password, password) - - + + def get_json(self): + return{ + 'id': self.id, + 'username': self.username, + 'role': self.role + } diff --git a/App/tests/test_app.py b/App/tests/test_app.py index fb95806b..1009ef40 100644 --- a/App/tests/test_app.py +++ b/App/tests/test_app.py @@ -48,15 +48,15 @@ def test_new_employer(self): def test_new_position(self): position = Position("Software Developer", 10, 5) assert position.title == "Software Developer" - assert position.employer_id == 10 + assert position.employerID == 10 assert position.status == "open" - assert position.number_of_positions == 5 + assert position.numberOfPositions == 5 def test_new_shortlist(self): shortlist = Shortlist(1,2,3) - assert shortlist.student_id == 1 - assert shortlist.position_id == 2 - assert shortlist.staff_id == 3 + assert shortlist.studentID == 1 + assert shortlist.positionID == 2 + assert shortlist.staffID == 3 assert shortlist.status == "pending" # pure function no side effects or integrations called @@ -123,9 +123,9 @@ def test_open_position(self): position = open_position("IT Support", employer.id, position_count) positions = get_positions_by_employer(employer.id) assert position is not None - assert position.number_of_positions == position_count + assert position.numberOfPositions == position_count assert len(positions) > 0 - assert any(p.id == position.id for p in positions) + assert any(p.positionID == position.positionID for p in positions) invalid_position = open_position("Developer",-1,1) assert invalid_position is False @@ -142,11 +142,11 @@ def test_add_to_shortlist(self): position = open_position("Database Manager", employer.id, position_count) invalid_position = open_position("Developer",-1,1) assert invalid_position is False - added_shortlist = add_student_to_shortlist(student.id, position.id ,staff.id) + added_shortlist = add_student_to_shortlist(student.id, position.positionID ,staff.id) assert position is not None assert (added_shortlist) shortlists = get_shortlist_by_student(student.id) - assert any(s.id == added_shortlist.id for s in shortlists) + assert any(s.shortlistID == added_shortlist.shortlistID for s in shortlists) def test_decide_shortlist(self): @@ -159,13 +159,13 @@ def test_decide_shortlist(self): assert employer is not None position = open_position("Intern", employer.id, position_count) assert position is not None - stud_shortlist = add_student_to_shortlist(student.id, position.id ,staff.id) + stud_shortlist = add_student_to_shortlist(student.id, position.positionID ,staff.id) assert (stud_shortlist) - decided_shortlist = decide_shortlist(student.id, position.id, "accepted") + decided_shortlist = decide_shortlist(student.id, position.positionID, "accepted") assert (decided_shortlist) shortlists = get_shortlist_by_student(student.id) assert any(s.status == PositionStatus.accepted for s in shortlists) - assert position.number_of_positions == (position_count-1) + assert position.numberOfPositions == (position_count-1) assert len(shortlists) > 0 invalid_decision = decide_shortlist(-1, -1, "accepted") assert invalid_decision is False @@ -181,9 +181,9 @@ def test_student_view_shortlist(self): assert employer is not None position = open_position("Software Intern", employer.id, 4) assert position is not None - shortlist = add_student_to_shortlist(student.id, position.id ,staff.id) + shortlist = add_student_to_shortlist(student.id, position.positionID ,staff.id) shortlists = get_shortlist_by_student(student.id) - assert any(shortlist.id == s.id for s in shortlists) + assert any(shortlist.shortlistID == s.shortlistID for s in shortlists) assert len(shortlists) > 0 # Tests data changes in the database diff --git a/App/views/position.py b/App/views/position.py index ed4f55e9..68c9f6ee 100644 --- a/App/views/position.py +++ b/App/views/position.py @@ -1,6 +1,6 @@ from flask import Blueprint, jsonify, request from flask_jwt_extended import jwt_required, current_user -from App.controllers import (open_position, get_positions_by_employer, get_all_positions_json, get_positions_by_employer_json) +from App.controllers import (viewAvailablePositions, get_positions_by_employer, get_all_positions_json, get_positions_by_employer_json) position_views = Blueprint('position_views', __name__) @@ -18,7 +18,7 @@ def create_position(): return jsonify({"message": "Unauthorized user"}), 403 data = request.json - position = open_position(title=data['title'], user_id=current_user.id, number_of_positions=data['number']) + # position = open_position(title=data['title'], user_id=current_user.id, number_of_positions=data['number']) if position: return jsonify(position.toJSON()), 201 diff --git a/App/views/user.py b/App/views/user.py index aeb60076..ce1868e6 100644 --- a/App/views/user.py +++ b/App/views/user.py @@ -5,8 +5,8 @@ from App.controllers import ( create_user, - get_all_users, - get_all_users_json, + # get_all_users, + # get_all_users_json, jwt_required ) diff --git a/wsgi.py b/wsgi.py index 2e498401..762263db 100644 --- a/wsgi.py +++ b/wsgi.py @@ -4,7 +4,7 @@ from App.database import db, get_migrate from App.models import User from App.main import create_app -from App.controllers import ( create_user, get_all_users_json, get_all_users, initialize, open_position, add_student_to_shortlist, decide_shortlist, get_shortlist_by_student, get_shortlist_by_position, get_positions_by_employer) +from App.controllers import ( create_user, login, check_password ,set_password, initialize,viewAvailablePositions, addToshortlist,viewShortlist, updateStatus, createPosition, editPosition, makeDecision, viewApplicants, getPositionsByEmployer, shortlistedByPosition, shortlistedStudent) # This commands file allow you to create convenient CLI commands for testing controllers @@ -96,7 +96,7 @@ def get_shortlist_command(student_id): list = get_shortlist_by_student(student_id) if list: for item in list: - print(f'Student {item.student_id} is {item.status.value} for position {item.position_id}') + print(f'Student {item.studentID} is {item.status.value} for position {item.positionID}') print("\n\n__________________________________________________________________________\n\n") else: @@ -109,11 +109,11 @@ def get_shortlist_by_position_command(position_id): list = get_shortlist_by_position(position_id) if list: for item in list: - print(f'Student {item.student_id} is {item.status.value} for {item.position.title} id: {item.position_id}') - print(f' Staff {item.staff_id} added this student to the shortlist') - print(f' Position {item.position_id} is {item.position.status.value}') - print(f' Position {item.position_id} has {item.position.number_of_positions} slots') - print(f' Position {item.position_id} is for {item.position.title}') + print(f'Student {item.studentID} is {item.status.value} for {item.position.title} id: {item.positionID}') + print(f' Staff {item.staffID} added this student to the shortlist') + print(f' Position {item.positionID} is {item.position.status.value}') + print(f' Position {item.positionID} has {item.position.number_of_positions} slots') + print(f' Position {item.positionID} is for {item.position.title}') print("\n\n__________________________________________________________________________\n\n") else: @@ -126,9 +126,9 @@ def get_positions_by_employer_command(employer_id): list = get_positions_by_employer(employer_id) if list: for item in list: - print(f'Position {item.id} is {item.status.value}') - print(f' Position {item.id} has {item.number_of_positions} slots') - print(f' Position {item.id} is for {item.title}') + print(f'Position {item.positionID} is {item.status.value}') + print(f' Position {item.positionID} has {item.numberOfPositions} slots') + print(f' Position {item.positionID} is for {item.title}') print("\n\n__________________________________________________________________________\n\n") else: print(f'Employer {employer_id} has no positions')