diff --git a/.python-version b/.python-version deleted file mode 100644 index 0a590336d..000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.9.10 diff --git a/App/controllers/initialize.py b/App/controllers/initialize.py index 9194d3aba..62c8298bc 100644 --- a/App/controllers/initialize.py +++ b/App/controllers/initialize.py @@ -1,8 +1,10 @@ -from .user import create_user +from .user import create_student, create_employer, create_staff from App.database import db def initialize(): db.drop_all() db.create_all() - create_user('bob', 'bobpass') + create_student('student', 'studentpass', 'UWI', 'Computer Science', 3.5) + create_employer('employer', 'employerpass') + create_staff('staff', 'staffpass') diff --git a/App/controllers/user.py b/App/controllers/user.py index 47b346edf..ecef0cc22 100644 --- a/App/controllers/user.py +++ b/App/controllers/user.py @@ -1,11 +1,35 @@ -from App.models import User +from App.models import Employer,Staff,Student from App.database import db -def create_user(username, password): - newuser = User(username=username, password=password) - db.session.add(newuser) - db.session.commit() - return newuser +def create_employer(username, password): + newemployer = Employer(username=username, password=password) + try: + db.session.add(newemployer) + db.session.commit() + return newemployer + except: + db.session.rollback() + return None + +def create_staff(username, password): + newstaff = Staff(username=username, password=password) + try: + db.session.add(newstaff) + db.session.commit() + return newstaff + except: + db.session.rollback() + return None + +def create_student(username, password, university, degree, gpa): + newstudent = Student(username=username, password=password, university=university, degree=degree, gpa=gpa) + try: + db.session.add(newstudent) + db.session.commit() + return newstudent + except: + db.session.rollback() + return None def get_user_by_username(username): result = db.session.execute(db.select(User).filter_by(username=username)) diff --git a/App/models/__init__.py b/App/models/__init__.py index 82da278c5..f526ad26e 100644 --- a/App/models/__init__.py +++ b/App/models/__init__.py @@ -1 +1,6 @@ -from .user import * \ No newline at end of file +from .user import * +from .employer import * +from .staff import * +from .student import * +from .internship import * +from .shortlist import * \ No newline at end of file diff --git a/App/models/employer.py b/App/models/employer.py new file mode 100644 index 000000000..b8600298f --- /dev/null +++ b/App/models/employer.py @@ -0,0 +1,28 @@ +from App.database import db +from .user import User + +class Employer(User): + __tablename__ = 'employer' + + id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + + internship = db.relationship('Internship', backref=db.backref('employer', lazy='joined')) + + __mapper_args__ = { + "polymorphic_identity": 'employer', + } + + def __init__(self, username, password): + self.username = username + self.set_password(password) + self.role = "employer" + + def get_json(self): + return { + "id": self.id, + "username": self.username, + "role": self.role, + } + + + diff --git a/App/models/internship.py b/App/models/internship.py new file mode 100644 index 000000000..90a1ba1a1 --- /dev/null +++ b/App/models/internship.py @@ -0,0 +1,24 @@ +from App.database import db + +class Internship(db.Model): + internship_id = db.Column(db.Integer, primary_key=True) + employer_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + title = db.Column(db.String(100), nullable=False) + description = db.Column(db.Text, nullable=False) + + shortlist = db.relationship('Shortlist', backref=db.backref('internship', lazy='joined')) + + def __init__(self, title, description, employer_id): + self.title = title + self.description = description + self.employer_id = employer_id + + def get_json(self): + return { + 'internship_id': self.internship_id, + 'title': self.title, + 'description': self.description, + 'employer_id': self.employer_id + } + + diff --git a/App/models/shortlist.py b/App/models/shortlist.py new file mode 100644 index 000000000..dc56c2a45 --- /dev/null +++ b/App/models/shortlist.py @@ -0,0 +1,27 @@ +from App.database import db + +class Shortlist(db.Model): + + shortlist_id = db.Column(db.Integer, primary_key=True) + internship_id = db.Column(db.Integer, db.ForeignKey('internship.internship_id'), nullable=False) # FIXED + staff_id = db.Column(db.Integer, db.ForeignKey('staff.id'), nullable=True) + student_id = db.Column(db.Integer, db.ForeignKey('student.id'), nullable=True) + status = db.Column(db.String(50), nullable=True) # accepted, rejected + + + def __init__(self, internship_id, staff_id, student_id, status=None): + self.internship_id = internship_id + self.staff_id = staff_id + self.student_id = student_id + self.status = status + + def get_json(self): + return { + 'shortlist_id': self.shortlist_id, + 'internship_id': self.internship_id, + 'staff_id': self.staff_id, + 'student_id': self.student_id, + 'status': self.status + + } + diff --git a/App/models/staff.py b/App/models/staff.py new file mode 100644 index 000000000..e094718c9 --- /dev/null +++ b/App/models/staff.py @@ -0,0 +1,28 @@ +from App.database import db +from .user import User + +class Staff(User): + __tablename__ = 'staff' + + id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + + shortlist = db.relationship('Shortlist', backref=db.backref('staff', lazy='joined')) + + __mapper_args__ = { + "polymorphic_identity": 'staff', + } + + def __init__(self, username, password): + self.username = username + self.set_password(password) + self.role = "staff" + + def get_json(self): + return { + "id": self.id, + "username": self.username, + "role": self.role + } + + + diff --git a/App/models/student.py b/App/models/student.py new file mode 100644 index 000000000..4f11143f4 --- /dev/null +++ b/App/models/student.py @@ -0,0 +1,32 @@ +from App.database import db +from .user import User + +class Student(User): + __tablename__ = 'student' + + id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True) + university = db.Column(db.String(100), nullable=False) + degree = db.Column(db.String(100), nullable=False) + gpa = db.Column(db.Float, nullable=False) + + __mapper_args__ = { + 'polymorphic_identity': 'student', + } + + def __init__(self, username, password, university, degree, gpa): + self.username = username + self.set_password(password) + self.role = "student" + self.university = university + self.degree = degree + self.gpa = gpa + + def get_json(self): + return { + 'id': self.id, + 'username': self.username, + 'university': self.university, + 'degree': self.degree, + 'gpa': self.gpa + } + diff --git a/App/models/user.py b/App/models/user.py index 9ed25ad10..56ec590ee 100644 --- a/App/models/user.py +++ b/App/models/user.py @@ -2,18 +2,27 @@ from App.database import db 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(20), nullable=False) # 'student', 'employer', 'staff' + + __mapper_args__ = { + 'polymorphic_identity': 'user', + 'polymorphic_on': role, + } - def __init__(self, username, password): + def __init__(self, username, password, role): self.username = username self.set_password(password) + self.role = role def get_json(self): return{ 'id': self.id, - 'username': self.username + 'username': self.username, + 'role': self.role } def set_password(self, password): diff --git a/App/views/index.py b/App/views/index.py index 7e5820190..60b3f8640 100644 --- a/App/views/index.py +++ b/App/views/index.py @@ -1,5 +1,5 @@ from flask import Blueprint, redirect, render_template, request, send_from_directory, jsonify -from App.controllers import create_user, initialize +from App.controllers import create_employer, create_staff, create_student, initialize index_views = Blueprint('index_views', __name__, template_folder='../templates') diff --git a/App/views/user.py b/App/views/user.py index aeb60076b..bd15d35aa 100644 --- a/App/views/user.py +++ b/App/views/user.py @@ -4,7 +4,9 @@ from.index import index_views from App.controllers import ( - create_user, + create_employer, + create_staff, + create_student, get_all_users, get_all_users_json, jwt_required diff --git a/readme.md b/readme.md index 872642e5b..650d23b2b 100644 --- a/readme.md +++ b/readme.md @@ -64,23 +64,246 @@ You just need create a manager command function, for example: user_cli = AppGroup('user', help='User object commands') -@user_cli.cli.command("create-user") -@click.argument("username") -@click.argument("password") -def create_user_command(username, password): - create_user(username, password) - print(f'{username} created!') +@user_cli.command("create_employer", help="Creates an employer") +@click.argument("username", default="rob") +@click.argument("password", default="robpass") +def create_employer_command(username, password): + create_employer(username, password) + print(f'employer : {username} created!') -app.cli.add_command(user_cli) # add the group to the cli +``` + +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask user create_employer bob bobpass + + +@user_cli.command("create_staff", help="Creates a staff") +@click.argument("username", default="bob") +@click.argument("password", default="bobpass") +def create_staff_command(username, password): + create_staff(username, password) + print(f'staff : {username} created!') +``` + +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask user create_staff tom tompass + +@user_cli.command("create_student", help="Creates a student") +@click.argument("username", default="ben") +@click.argument("password", default="benpass") +@click.argument("university", default="UWI") +@click.argument("degree", nargs=-1) +@click.argument("gpa", default=3.5) +def create_student_command(username, password, university, degree, gpa): + create_student(username, password, university, degree, gpa) + print(f'student : {username} created!') ``` Then execute the command invoking with flask cli with command name and the relevant parameters ```bash -$ flask user create bob bobpass + +$ flask user create_student tim timpass UWI Computer Science 3.5 + + +@app.cli.command("create-internship", help="Create an internship for an employer") +def create_internship(): + username = input("Enter your username: ") + + user = Employer.query.filter_by(username=username).first() + if not user: + print(f"User with username '{username}' not found.") + return + + internship_input = input("Enter the title and description of the internship (separated by a comma): ") + title, description = [item.strip() for item in internship_input.split(",", 1)] + if not title or not description: + print("Both title and description are required.") + return + new_internship = Internship(title=title, description=description, employer_id=user.id) + db.session.add(new_internship) + db.session.commit() + print(f" Internship '{title}' created for employer '{username}'.") + ``` +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask create-internship + + +@app.cli.command("add-student", help="Lets a staff add a student to a shortlist") +def add_student(): + staff_username = input("Enter your staff username: ") + staff = Staff.query.filter_by(username=staff_username).first() + if not staff: + print(f"Staff with username '{staff_username}' not found.") + return + + internships = Internship.query.all() + if not internships: + print("No internships found.") + else: + print("Available Internships:") + for internship in internships: + print(f"ID: {internship.internship_id}, Title: {internship.title}") + + students = Student.query.all() + if not students: + print("No students found.") + else: + print("\nAvailable Students:") + for student in students: + print(f"Username: {student.username}, University: {student.university}, Degree: {student.degree}, GPA: {student.gpa}") + + internship_title = input("\nEnter the title of the internship to shortlist a student for: ") + internship = Internship.query.filter_by(title=internship_title).first() + if not internship: + print(f"Internship with title '{internship_title}' not found.") + return + + student_username = input("Enter the student's username to add to the shortlist: ") + student = Student.query.filter_by(username=student_username).first() + if not student: + print(f"Student with username '{student_username}' not found.") + return + + shortlist_entry = Shortlist( + internship_id=internship.internship_id, + staff_id=staff.id, + student_id=student.id, + status="pending" + ) + db.session.add(shortlist_entry) + db.session.commit() + print(f"Student '{student_username}' added to the shortlist for internship '{internship_title}' by staff '{staff_username}' with status 'pending'.") + +``` + +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask add-student + + +@app.cli.command("set-status", help="Lets an employer set the status of a student in a shortlist") +def set_status(): + + employer_username = input("Enter your employer username: ") + employer = Employer.query.filter_by(username=employer_username).first() + if not employer: + print(f"Employer with username '{employer_username}' not found.") + return + + internships = Internship.query.filter_by(employer_id=employer.id).all() + if not internships: + print("No internships found for this employer.") + return + print("Available Internships:") + for internship in internships: + print(f"ID: {internship.internship_id}, Title: {internship.title}") + + internship_id = input("\nEnter the ID of the internship to manage its shortlist: ") + internship = Internship.query.get(internship_id) + if not internship or internship.employer_id != employer.id: + print(f"Internship with ID '{internship_id}' not found for this employer.") + return + + shortlist_entries = Shortlist.query.filter_by(internship_id=internship_id).all() + if not shortlist_entries: + print(f"No students in the shortlist for internship '{internship.title}'.") + return + + print("\nShortlist Entries:") + for entry in shortlist_entries: + student = Student.query.get(entry.student_id) + if student: + print(f"Shortlist ID: {entry.shortlist_id}, " + f"Student ID: {student.id}, " + f"Username: {student.username}, " + f"University: {student.university}, " + f"Degree: {student.degree}, " + f"GPA: {student.gpa}, " + f"Status: {entry.status}") + else: + print(f"Shortlist ID: {entry.shortlist_id}, Student not found, Status: {entry.status}") + + student_id_input = input("\nEnter the student's ID to update status: ") + try: + student_id = int(student_id_input) + except ValueError: + print("Invalid ID. Must be an integer.") + return + + student = Student.query.get(student_id) + if not student: + print(f"Student with ID '{student_id}' not found.") + return + + shortlist_entry = Shortlist.query.filter_by(internship_id=internship_id, student_id=student.id).first() + if not shortlist_entry: + print(f"Shortlist entry for student ID '{student_id}' not found in this internship.") + return + + new_status = input("Enter the new status (accept/reject): ").lower() + if new_status not in ["accept", "reject"]: + print("Invalid status. Please enter 'accept' or 'reject'.") + return + + shortlist_entry.status = new_status + db.session.commit() + print(f"Status of student '{student.username}' (ID: {student.id}) for internship '{internship.title}' updated to '{new_status}'.") + +``` + +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask set-status + + +@app.cli.command("view-shortlists", help="Lets students view their shortlists and statuses") +def view_shortlists(): + student_username = input("Enter your student username: ") + student = Student.query.filter_by(username=student_username).first() + if not student: + print(f"Student with username '{student_username}' not found.") + return + + shortlist_entries = Shortlist.query.filter_by(student_id=student.id).all() + if not shortlist_entries: + print("No shortlist entries found for this student.") + return + + print(f"\nShortlist Entries for {student.username}:") + for entry in shortlist_entries: + internship = Internship.query.get(entry.internship_id) + if internship: + print(f"Internship Title: {internship.title}, Internship Description: {internship.description}, Status: {entry.status}") + else: + print(f"Internship not found for Shortlist ID: {entry.shortlist_id}, Status: {entry.status}") + + +``` + +Then execute the command invoking with flask cli with command name and the relevant parameters + +```bash + +$ flask view-shortlists + + # Running the Project diff --git a/wsgi.py b/wsgi.py index a14d5778b..6a70a18e2 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,10 +1,16 @@ import click, pytest, sys from flask.cli import with_appcontext, AppGroup - -from App.database import db, get_migrate -from App.models import User +from App.database import create_db, db, get_migrate +from App.models import (User, Employer, Staff, Student, Shortlist, Internship, internship) from App.main import create_app -from App.controllers import ( create_user, get_all_users_json, get_all_users, initialize ) +from App.controllers import ( + + create_employer, + create_staff, + create_student, + get_all_users_json, + get_all_users, initialize +) # This commands file allow you to create convenient CLI commands for testing controllers @@ -15,12 +21,178 @@ # This command creates and initializes the database @app.cli.command("init", help="Creates and initializes the database") def init(): - initialize() + db.drop_all() + db.create_all() + mally = Employer(username='mally', password='mallypass') + nicki = Employer(username='nicki', password='nickipass') + cardi = Employer(username='cardi', password='cardipass') + drake = Staff(username='drake', password='drakepass') + wayne = Staff(username='wayne', password='waynepass') + kai = Staff(username='kai', password='kaipass') + ben = Student(username='ben', password='benpass', university='UWI', degree='Computer Science', gpa=3.5) + angela = Student(username='angela', password='angelapass', university='UTT', degree='Finance', gpa=3.8) + bella = Student(username='bella', password='bellapass', university='UWI', degree='Finance', gpa=3.6) + db.session.add_all([mally, nicki, cardi, drake, wayne, kai, ben, angela, bella]) + db.session.commit() print('database intialized') -''' -User Commands -''' + +@app.cli.command("create-internship", help="Create an internship for an employer") +def create_internship(): + username = input("Enter your username: ") + + user = Employer.query.filter_by(username=username).first() + if not user: + print(f"User with username '{username}' not found.") + return + + internship_input = input("Enter the title and description of the internship (separated by a comma): ") + title, description = [item.strip() for item in internship_input.split(",", 1)] + if not title or not description: + print("Both title and description are required.") + return + new_internship = Internship(title=title, description=description, employer_id=user.id) + db.session.add(new_internship) + db.session.commit() + print(f" Internship '{title}' created for employer '{username}'.") + + +@app.cli.command("add-student", help="Lets a staff add a student to a shortlist") +def add_student(): + staff_username = input("Enter your staff username: ") + staff = Staff.query.filter_by(username=staff_username).first() + if not staff: + print(f"Staff with username '{staff_username}' not found.") + return + + internships = Internship.query.all() + if not internships: + print("No internships found.") + else: + print("Available Internships:") + for internship in internships: + print(f"ID: {internship.internship_id}, Title: {internship.title}") + + students = Student.query.all() + if not students: + print("No students found.") + else: + print("\nAvailable Students:") + for student in students: + print(f"Username: {student.username}, University: {student.university}, Degree: {student.degree}, GPA: {student.gpa}") + + internship_title = input("\nEnter the title of the internship to shortlist a student for: ") + internship = Internship.query.filter_by(title=internship_title).first() + if not internship: + print(f"Internship with title '{internship_title}' not found.") + return + + student_username = input("Enter the student's username to add to the shortlist: ") + student = Student.query.filter_by(username=student_username).first() + if not student: + print(f"Student with username '{student_username}' not found.") + return + + shortlist_entry = Shortlist( + internship_id=internship.internship_id, + staff_id=staff.id, + student_id=student.id, + status="pending" + ) + db.session.add(shortlist_entry) + db.session.commit() + print(f"Student '{student_username}' added to the shortlist for internship '{internship_title}' by staff '{staff_username}' with status 'pending'.") + +@app.cli.command("set-status", help="Lets an employer set the status of a student in a shortlist") +def set_status(): + + employer_username = input("Enter your employer username: ") + employer = Employer.query.filter_by(username=employer_username).first() + if not employer: + print(f"Employer with username '{employer_username}' not found.") + return + + internships = Internship.query.filter_by(employer_id=employer.id).all() + if not internships: + print("No internships found for this employer.") + return + print("Available Internships:") + for internship in internships: + print(f"ID: {internship.internship_id}, Title: {internship.title}") + + internship_id = input("\nEnter the ID of the internship to manage its shortlist: ") + internship = Internship.query.get(internship_id) + if not internship or internship.employer_id != employer.id: + print(f"Internship with ID '{internship_id}' not found for this employer.") + return + + shortlist_entries = Shortlist.query.filter_by(internship_id=internship_id).all() + if not shortlist_entries: + print(f"No students in the shortlist for internship '{internship.title}'.") + return + + print("\nShortlist Entries:") + for entry in shortlist_entries: + student = Student.query.get(entry.student_id) + if student: + print(f"Shortlist ID: {entry.shortlist_id}, " + f"Student ID: {student.id}, " + f"Username: {student.username}, " + f"University: {student.university}, " + f"Degree: {student.degree}, " + f"GPA: {student.gpa}, " + f"Status: {entry.status}") + else: + print(f"Shortlist ID: {entry.shortlist_id}, Student not found, Status: {entry.status}") + + student_id_input = input("\nEnter the student's ID to update status: ") + try: + student_id = int(student_id_input) + except ValueError: + print("Invalid ID. Must be an integer.") + return + + student = Student.query.get(student_id) + if not student: + print(f"Student with ID '{student_id}' not found.") + return + + shortlist_entry = Shortlist.query.filter_by(internship_id=internship_id, student_id=student.id).first() + if not shortlist_entry: + print(f"Shortlist entry for student ID '{student_id}' not found in this internship.") + return + + new_status = input("Enter the new status (accepted/rejected): ").lower() + if new_status not in ["accepted", "rejected"]: + print("Invalid status. Please enter 'accepted' or 'rejected'.") + return + + shortlist_entry.status = new_status + db.session.commit() + print(f"Status of student '{student.username}' (ID: {student.id}) for internship '{internship.title}' updated to '{new_status}'.") + +@app.cli.command("view-shortlists", help="Lets students view their shortlists and statuses") +def view_shortlists(): + student_username = input("Enter your student username: ") + student = Student.query.filter_by(username=student_username).first() + if not student: + print(f"Student with username '{student_username}' not found.") + return + + shortlist_entries = Shortlist.query.filter_by(student_id=student.id).all() + if not shortlist_entries: + print("No shortlist entries found for this student.") + return + + print(f"\nShortlist Entries for {student.username}:") + for entry in shortlist_entries: + internship = Internship.query.get(entry.internship_id) + if internship: + print(f"Internship Title: {internship.title}, Internship Description: {internship.description}, Status: {entry.status}") + else: + print(f"Internship not found for Shortlist ID: {entry.shortlist_id}, Status: {entry.status}") + +#"""User Commands""" # Commands can be organized using groups @@ -29,14 +201,33 @@ def init(): user_cli = AppGroup('user', help='User object commands') # Then define the command and any parameters and annotate it with the group (@) -@user_cli.command("create", help="Creates a user") +@user_cli.command("create_employer", help="Creates an employer") @click.argument("username", default="rob") @click.argument("password", default="robpass") -def create_user_command(username, password): - create_user(username, password) - print(f'{username} created!') +def create_employer_command(username, password): + create_employer(username, password) + print(f'employer : {username} created!') + + +@user_cli.command("create_staff", help="Creates a staff") +@click.argument("username", default="bob") +@click.argument("password", default="bobpass") +def create_staff_command(username, password): + create_staff(username, password) + print(f'staff : {username} created!') + + +@user_cli.command("create_student", help="Creates a student") +@click.argument("username", default="ben") +@click.argument("password", default="benpass") +@click.argument("university", default="UWI") +@click.argument("degree", nargs=-1) +@click.argument("gpa", default=3.5) +def create_student_command(username, password, university, degree, gpa): + create_student(username, password, university, degree, gpa) + print(f'student : {username} created!') -# this command will be : flask user create bob bobpass +# this command will be : flask user create_student ben benpass UWI "Computer Science" 3.5 @user_cli.command("list", help="Lists users in the database") @click.argument("format", default="string")