add year group and change logic of endpoints v2

This commit is contained in:
dominik24c 2022-11-12 16:18:07 +01:00
parent 82807b7c2e
commit eea98dd225
32 changed files with 762 additions and 291 deletions

View File

@ -13,4 +13,3 @@ COPY requirements.txt .
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
COPY . . COPY . .

7
backend/app/base/mode.py Normal file
View File

@ -0,0 +1,7 @@
from enum import Enum
class ModeGroups(str, Enum):
STATIONARY = 's'
NON_STATIONARY = 'n'
ENGLISH_SPEAKING_STATIONARY = 'e'

View File

@ -2,7 +2,7 @@ from flask.cli import with_appcontext
from click import command from click import command
from ..dependencies import db from ..dependencies import db
from ..factory import ProjectSupervisorFactory, GroupFactory, StudentFactory # from ..factory import ProjectSupervisorFactory, GroupFactory, StudentFactory
@command('init_db') @command('init_db')
@ -11,27 +11,27 @@ def init_db() -> None:
"""Fill database with some data""" """Fill database with some data"""
db.drop_all() db.drop_all()
db.create_all() db.create_all()
#
num_of_supervisors = 5 # num_of_supervisors = 5
#
projects_supervisors = [ProjectSupervisorFactory() for _ in range(num_of_supervisors)] # projects_supervisors = [ProjectSupervisorFactory() for _ in range(num_of_supervisors)]
db.session.add_all(projects_supervisors) # db.session.add_all(projects_supervisors)
db.session.commit() # db.session.commit()
#
groups = [GroupFactory(project_supervisor=projects_supervisors[i]) for i in range(num_of_supervisors)] # groups = [GroupFactory(project_supervisor=projects_supervisors[i]) for i in range(num_of_supervisors)]
db.session.add_all(groups) # db.session.add_all(groups)
db.session.commit() # db.session.commit()
#
num_of_students = num_of_supervisors * 3 # num_of_students = num_of_supervisors * 3
students = [StudentFactory(group=groups[i % num_of_supervisors]) for i in range(num_of_students)] # students = [StudentFactory(group=groups[i % num_of_supervisors]) for i in range(num_of_students)]
#
max_count = 10 # max_count = 10
max_length = len(students) # max_length = len(students)
start_count = 0 # start_count = 0
#
while True: # while True:
if start_count > max_length: # if start_count > max_length:
break # break
db.session.add_all(students[start_count:max_count]) # db.session.add_all(students[start_count:max_count])
db.session.commit() # db.session.commit()
start_count += max_count # start_count += max_count

View File

@ -1,17 +1,19 @@
from flask import Blueprint from flask import Blueprint
from .examination_schedule import bp as examination_schedule_bp from .examination_schedule import bp as examination_schedule_bp
from .enrollments import bp as enrollments_bp # from .enrollments import bp as enrollments_bp
from .groups import bp as groups_bp from .groups import bp as groups_bp
from .project_supervisor import bp as project_supervisor_bp from .project_supervisor import bp as project_supervisor_bp
from .students import bp as students_bp from .students import bp as students_bp
from .workloads import bp as workloads_bp from .year_group import bp as year_group_bp
# from .workloads import bp as workloads_bp
bp = Blueprint("coordinator", __name__, url_prefix="/coordinator") bp = Blueprint("coordinator", __name__, url_prefix="/coordinator")
bp.register_blueprint(students_bp) bp.register_blueprint(students_bp)
bp.register_blueprint(project_supervisor_bp) bp.register_blueprint(project_supervisor_bp)
bp.register_blueprint(groups_bp) bp.register_blueprint(groups_bp)
bp.register_blueprint(year_group_bp)
bp.register_blueprint(examination_schedule_bp) bp.register_blueprint(examination_schedule_bp)
bp.register_blueprint(enrollments_bp) # bp.register_blueprint(enrollments_bp)
bp.register_blueprint(workloads_bp) # bp.register_blueprint(workloads_bp)

View File

@ -4,7 +4,7 @@ from apiflask import APIBlueprint
from flask import abort, current_app from flask import abort, current_app
from ..schemas import MessageSchema, EnrollmentCreateSchema from ..schemas import MessageSchema, EnrollmentCreateSchema
from ...examination_schedule.models import Enrollment, Committee, ExaminationSchedule from ...examination_schedule.models import ExaminationSchedule
from ...dependencies import db from ...dependencies import db
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")

View File

@ -5,8 +5,8 @@ from flask import abort, Response, make_response
from ...base.utils import paginate_models from ...base.utils import paginate_models
from ...dependencies import db from ...dependencies import db
from ...examination_schedule.models import ExaminationSchedule, Enrollment from ...examination_schedule.models import ExaminationSchedule
from ...students.models import Group from ...students.models import Group, YearGroup
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor
from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, MessageSchema, \ from ..schemas import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, MessageSchema, \
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
@ -15,21 +15,29 @@ from ..utils import generate_examination_schedule_pdf_file
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule") bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
@bp.get('/') @bp.get('/<int:year_group_id>/')
@bp.input(ExaminationSchedulesQuerySchema, location='query') @bp.input(ExaminationSchedulesQuerySchema, location='query')
@bp.output(ExaminationSchedulesPaginationSchema) @bp.output(ExaminationSchedulesPaginationSchema)
def list_examination_schedule(query: dict) -> dict: def list_examination_schedule(year_group_id: int, query: dict) -> dict:
page = query.get('page') page = query.get('page')
per_page = query.get('per_page') per_page = query.get('per_page')
data = paginate_models(page, ExaminationSchedule.query, per_page) es_query = ExaminationSchedule.query.filter(ExaminationSchedule.year_group_id == year_group_id)
data = paginate_models(page, es_query, per_page)
return {'examination_schedules': data['items'], 'max_pages': data['max_pages']} return {'examination_schedules': data['items'], 'max_pages': data['max_pages']}
@bp.post('/') @bp.post('/<int:year_group_id>/')
@bp.input(ExaminationScheduleSchema) @bp.input(ExaminationScheduleSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def create_examination_schedule(data: dict) -> dict: def create_examination_schedule(year_group_id: int, data: dict) -> dict:
examination_schedule = ExaminationSchedule(**data) yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
if yg is None:
abort(404, "Year group doesn't exist!")
if data['start_date'] > data['end_date']:
abort(400, "Invalid data! End date must be greater than start date!")
examination_schedule = ExaminationSchedule(**data, year_group_id=year_group_id)
db.session.add(examination_schedule) db.session.add(examination_schedule)
db.session.commit() db.session.commit()
return {"message": "Examination schedule was created!"} return {"message": "Examination schedule was created!"}
@ -70,7 +78,7 @@ def set_date_of_examination_schedule(id: int, data: dict) -> dict:
if examination_schedule is None: if examination_schedule is None:
abort(404, "Examination schedule doesn't exist!") abort(404, "Examination schedule doesn't exist!")
if data['start_date'] > data['end_date']: if data['start_date_for_enrollment_students'] > data['end_date_for_enrollment_students']:
abort(400, "Invalid data! End date must be greater than start date!") abort(400, "Invalid data! End date must be greater than start date!")
examination_schedule_query.update(data) examination_schedule_query.update(data)
@ -91,7 +99,7 @@ def download_examination_schedule(examination_schedule_id: int) -> Response:
nested_enrollments = [] nested_enrollments = []
for d in distinct_dates: for d in distinct_dates:
date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date() date_tmp = datetime.datetime.strptime(d[0], "%Y-%m-%d").date()
enrollment = db.session.query(Enrollment).join(ExaminationSchedule, isouter=True).\ enrollment = db.session.query(Enrollment).join(ExaminationSchedule, isouter=True). \
join(Group, isouter=True).join(ProjectSupervisor, isouter=True). \ join(Group, isouter=True).join(ProjectSupervisor, isouter=True). \
filter(ExaminationSchedule.id == examination_schedule_id).filter( filter(ExaminationSchedule.id == examination_schedule_id).filter(
db.func.Date(Enrollment.start_date) == date_tmp).all() db.func.Date(Enrollment.start_date) == date_tmp).all()

View File

@ -2,8 +2,8 @@ from flask import abort, current_app
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask_sqlalchemy import get_debug_queries from flask_sqlalchemy import get_debug_queries
from ...students.models import Group, Student from ...students.models import Group, Student, YearGroup
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
from ..schemas import GroupSchema, GroupEditSchema, GroupsPaginationSchema, \ from ..schemas import GroupSchema, GroupEditSchema, GroupsPaginationSchema, \
GroupCreateSchema, MessageSchema, GroupQuerySchema GroupCreateSchema, MessageSchema, GroupQuerySchema
from ...dependencies import db from ...dependencies import db
@ -12,15 +12,15 @@ from ...base.utils import paginate_models
bp = APIBlueprint("groups", __name__, url_prefix="/groups") bp = APIBlueprint("groups", __name__, url_prefix="/groups")
@bp.route("/", methods=["GET"]) @bp.get("/<int:year_group_id>/")
@bp.input(GroupQuerySchema, location='query') @bp.input(GroupQuerySchema, location='query')
@bp.output(GroupsPaginationSchema) @bp.output(GroupsPaginationSchema)
def list_groups(query: dict) -> dict: def list_groups(year_group_id: int, query: dict) -> dict:
search_name = query.get('name') search_name = query.get('name')
page = query.get('page') page = query.get('page')
per_page = query.get('per_page') per_page = query.get('per_page')
groups_query = Group.search_by_name(search_name) groups_query = Group.search_by_name(year_group_id, search_name)
data = paginate_models(page, groups_query, per_page) data = paginate_models(page, groups_query, per_page)
@ -30,14 +30,18 @@ def list_groups(query: dict) -> dict:
} }
@bp.route("/", methods=["POST"]) @bp.post("/<int:year_group_id>/")
@bp.input(GroupCreateSchema) @bp.input(GroupCreateSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def create_group(data: dict) -> dict: def create_group(year_group_id: int, data: dict) -> dict:
name = data['name'] name = data['name']
students_indexes = data['students'] students_indexes = data['students']
project_supervisor_id = data['project_supervisor_id'] project_supervisor_id = data['project_supervisor_id']
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
if yg is None:
abort(404, "YearGroup doesn't exist!")
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first() project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
limit_student_per_group = current_app.config.get('LIMIT_STUDENTS_PER_GROUP') limit_student_per_group = current_app.config.get('LIMIT_STUDENTS_PER_GROUP')
@ -47,13 +51,16 @@ def create_group(data: dict) -> dict:
abort(400, f"Too much students you want add to group, " abort(400, f"Too much students you want add to group, "
f"The group can have only {limit_student_per_group} students") f"The group can have only {limit_student_per_group} students")
limit = db.session.query(ProjectSupervisor.limit_group - db.func.count(ProjectSupervisor.id)).join(Group).filter( limit = db.session.query(db.func.count(ProjectSupervisor.id)). \
ProjectSupervisor.id == project_supervisor_id).group_by(ProjectSupervisor.id).scalar() join(Group).filter(ProjectSupervisor.id == project_supervisor_id).group_by(ProjectSupervisor.id).scalar()
if limit is not None and limit <= 0: ygps = YearGroupProjectSupervisors.query. \
filter(YearGroupProjectSupervisors.year_group_id == year_group_id,
YearGroupProjectSupervisors.project_supervisor_id == project_supervisor_id).first()
if limit is not None and ygps is not None and limit >= ygps.limit_group:
abort(400, "Can't create new group, project supervisor achieved a limit of groups") abort(400, "Can't create new group, project supervisor achieved a limit of groups")
group = Group(name=name, project_supervisor_id=project_supervisor_id) group = Group(name=name, project_supervisor_id=project_supervisor_id, year_group_id=year_group_id)
students_without_groups = db.session.query(Student).join(Group, isouter=True) \ students_without_groups = db.session.query(Student).join(Group, isouter=True) \
.filter(Group.id.is_(None)).filter(Student.index.in_(students_indexes)).count() .filter(Group.id.is_(None)).filter(Student.index.in_(students_indexes)).count()
@ -65,7 +72,6 @@ def create_group(data: dict) -> dict:
db.session.commit() db.session.commit()
students = db.session.query(Student).filter(Student.index.in_(students_indexes)).all() students = db.session.query(Student).filter(Student.index.in_(students_indexes)).all()
project_supervisor.count_groups += 1
for student in students: for student in students:
student.group_id = group.id student.group_id = group.id
@ -74,7 +80,7 @@ def create_group(data: dict) -> dict:
return {"message": "Group was created!"} return {"message": "Group was created!"}
@bp.route("/<int:id>/", methods=["GET"]) @bp.get("/<int:id>/")
@bp.output(GroupSchema) @bp.output(GroupSchema)
def detail_group(id: int) -> Group: def detail_group(id: int) -> Group:
group = Group.query.filter_by(id=id).first() group = Group.query.filter_by(id=id).first()
@ -83,16 +89,13 @@ def detail_group(id: int) -> Group:
return group return group
@bp.route("/<int:id>/", methods=["DELETE"]) @bp.delete("/<int:id>/")
@bp.output(MessageSchema, status_code=202) @bp.output(MessageSchema, status_code=202)
def delete_group(id: int) -> dict: def delete_group(id: int) -> dict:
group = Group.query.filter_by(id=id).first() group = Group.query.filter_by(id=id).first()
if group is None: if group is None:
abort(400, f"Group with id {id} doesn't exist!") abort(400, f"Group with id {id} doesn't exist!")
project_supervisor = ProjectSupervisor.query.filter_by(id=group.project_supervisor_id).first()
project_supervisor.count_groups -= 1
students = db.session.query(Student).filter_by(group_id=id).all() students = db.session.query(Student).filter_by(group_id=id).all()
for student in students: for student in students:
student.group_id = None student.group_id = None
@ -102,7 +105,7 @@ def delete_group(id: int) -> dict:
return {"message": "Group was deleted!"} return {"message": "Group was deleted!"}
@bp.route("/<int:id>", methods=["PUT"]) @bp.put("/<int:id>/")
@bp.input(GroupEditSchema) @bp.input(GroupEditSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def edit_group(id: int, data: dict) -> dict: def edit_group(id: int, data: dict) -> dict:

View File

@ -2,29 +2,28 @@ from flask import abort
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask_sqlalchemy import get_debug_queries from flask_sqlalchemy import get_debug_queries
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
from ...students.models import Group from ...students.models import Group, YearGroup
from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \ from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \
ProjectSupervisorCreateSchema, MessageSchema, ProjectSupervisorQuerySchema ProjectSupervisorCreateSchema, MessageSchema, ProjectSupervisorQuerySchema, ProjectSupervisorYearGroupSchema
from ...dependencies import db from ...dependencies import db
from ...base.utils import paginate_models from ...base.utils import paginate_models
bp = APIBlueprint("project_supervisor", __name__, url_prefix="/project_supervisor") bp = APIBlueprint("project_supervisor", __name__, url_prefix="/project_supervisor")
@bp.route("/", methods=["GET"]) @bp.get("/")
@bp.input(ProjectSupervisorQuerySchema, location='query') @bp.input(ProjectSupervisorQuerySchema, location='query')
@bp.output(ProjectSupervisorsPaginationSchema) @bp.output(ProjectSupervisorsPaginationSchema)
def list_project_supervisors(query: dict) -> dict: def list_project_supervisors(query: dict) -> dict:
fullname = query.get('fullname') fullname = query.get('fullname')
order_by_first_name = query.get('order_by_first_name') order_by_first_name = query.get('order_by_first_name')
order_by_last_name = query.get('order_by_last_name') order_by_last_name = query.get('order_by_last_name')
mode = query.get('mode')
page = query.get('page') page = query.get('page')
per_page = query.get('per_page') per_page = query.get('per_page')
project_supervisor_query = ProjectSupervisor.search_by_fullname_and_mode_and_order_by_first_name_or_last_name( project_supervisor_query = ProjectSupervisor.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
fullname, mode, order_by_first_name, order_by_last_name) None, fullname, order_by_first_name, order_by_last_name)
data = paginate_models(page, project_supervisor_query, per_page) data = paginate_models(page, project_supervisor_query, per_page)
# print(get_debug_queries()[0]) # print(get_debug_queries()[0])
@ -34,7 +33,28 @@ def list_project_supervisors(query: dict) -> dict:
} }
@bp.route("/", methods=["POST"]) @bp.get("/<int:year_group_id>/")
@bp.input(ProjectSupervisorQuerySchema, location='query')
@bp.output(ProjectSupervisorsPaginationSchema)
def list_project_supervisors_by_year_group(year_group_id: int, query: dict) -> dict:
fullname = query.get('fullname')
order_by_first_name = query.get('order_by_first_name')
order_by_last_name = query.get('order_by_last_name')
page = query.get('page')
per_page = query.get('per_page')
project_supervisor_query = ProjectSupervisor.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
year_group_id, fullname, order_by_first_name, order_by_last_name)
data = paginate_models(page, project_supervisor_query, per_page)
# print(get_debug_queries()[0])
return {
"project_supervisors": data['items'],
"max_pages": data['max_pages']
}
@bp.post("/")
@bp.input(ProjectSupervisorCreateSchema) @bp.input(ProjectSupervisorCreateSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def create_project_supervisor(data: dict) -> dict: def create_project_supervisor(data: dict) -> dict:
@ -52,7 +72,7 @@ def create_project_supervisor(data: dict) -> dict:
return {"message": "Project Supervisor was created!"} return {"message": "Project Supervisor was created!"}
@bp.route("/<int:id>/", methods=["GET"]) @bp.get("/<int:id>/")
@bp.output(ProjectSupervisorSchema) @bp.output(ProjectSupervisorSchema)
def detail_project_supervisor(id: int) -> ProjectSupervisor: def detail_project_supervisor(id: int) -> ProjectSupervisor:
project_supervisor = ProjectSupervisor.query.filter_by(id=id).first() project_supervisor = ProjectSupervisor.query.filter_by(id=id).first()
@ -61,25 +81,25 @@ def detail_project_supervisor(id: int) -> ProjectSupervisor:
return project_supervisor return project_supervisor
@bp.route("/<int:id>/", methods=["DELETE"]) @bp.delete("/<int:id>/")
@bp.output(MessageSchema, status_code=202) @bp.output(MessageSchema, status_code=202)
def delete_project_supervisor(id: int) -> dict: def delete_project_supervisor(id: int) -> dict:
project_supervisor = ProjectSupervisor.query.filter_by(id=id).first() project_supervisor = ProjectSupervisor.query.filter_by(id=id).first()
if project_supervisor is None: if project_supervisor is None:
abort(400, f"Project Supervisor with id {id} doesn't exist!") abort(400, f"Project Supervisor with id {id} doesn't exist!")
count_groups = db.session.query(db.func.count(ProjectSupervisor.id)).join(Group).\ count_groups = db.session.query(db.func.count(ProjectSupervisor.id)).join(Group). \
filter(ProjectSupervisor.id == id).group_by(ProjectSupervisor.id) filter(ProjectSupervisor.id == id).group_by(ProjectSupervisor.id)
if count_groups is not None: if count_groups is not None:
abort(400, f"Project Supervisor with id {id} has gropus!") abort(400, f"Project Supervisor with id {id} has groups!")
db.session.delete(project_supervisor) db.session.delete(project_supervisor)
db.session.commit() db.session.commit()
return {"message": "Project Supervisor was deleted!"} return {"message": "Project Supervisor was deleted!"}
@bp.route("/<int:id>", methods=["PUT"]) @bp.put("/<int:id>/")
@bp.input(ProjectSupervisorEditSchema) @bp.input(ProjectSupervisorEditSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def edit_project_supervisor(id: int, data: dict) -> dict: def edit_project_supervisor(id: int, data: dict) -> dict:
@ -95,3 +115,65 @@ def edit_project_supervisor(id: int, data: dict) -> dict:
project_supervisor_query.update(data) project_supervisor_query.update(data)
db.session.commit() db.session.commit()
return {"message": "Project Supervisor was updated!"} return {"message": "Project Supervisor was updated!"}
@bp.post("/<int:id>/year-group/<int:year_group_id>")
@bp.input(ProjectSupervisorYearGroupSchema)
@bp.output(MessageSchema)
def add_project_supervisor_to_year_group(id: int, year_group_id: int, data: dict) -> dict:
if not data:
abort(400, 'You have passed empty data!')
limit_group = data.get('limit_group')
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == id).first()
if project_supervisor is None:
abort(400, f"Project Supervisor with id {id} doesn't exist!")
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
if year_group is None:
abort(400, "Year group doesn't exist!")
ygps = YearGroupProjectSupervisors.query.filter(YearGroupProjectSupervisors.project_supervisor_id == id). \
filter(YearGroupProjectSupervisors.year_group_id == year_group_id).first()
if ygps is not None:
abort(400, "Project supervisor is assigned to this year group!")
ygps = YearGroupProjectSupervisors(year_group_id=year_group_id, project_supervisor_id=id,
limit_group=limit_group)
db.session.add(ygps)
db.session.commit()
return {"message": "Project Supervisor was added to year group!"}
@bp.delete("/<int:id>/year-group/<int:year_group_id>")
@bp.input(ProjectSupervisorYearGroupSchema)
@bp.output(MessageSchema)
def delete_project_supervisor_to_year_group(id: int, year_group_id: int) -> dict:
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == id). \
filter(YearGroup.id == year_group_id).first()
if project_supervisor is None:
abort(400, "Project Supervisor doesn't exist!")
ygps = YearGroupProjectSupervisors.query.filter(YearGroupProjectSupervisors.project_supervisor_id == id). \
filter(YearGroupProjectSupervisors.year_group_id == year_group_id).first()
db.session.delete(project_supervisor)
db.session.delete(ygps)
db.session.commit()
return {"message": "Project Supervisor was removed from this year group!"}
@bp.put("/<int:id>/year-group/<int:year_group_id>")
@bp.input(ProjectSupervisorYearGroupSchema)
@bp.output(MessageSchema)
def update_limit_of_group_for_project_supervisor(id: int, year_group_id: int, data: dict) -> dict:
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.id == id). \
filter(YearGroup.id == year_group_id).first()
if project_supervisor is None:
abort(400, "Project Supervisor doesn't exist!")
ygps = YearGroupProjectSupervisors.query.filter(YearGroupProjectSupervisors.project_supervisor_id == id). \
filter(YearGroupProjectSupervisors.year_group_id == year_group_id)
ygps.update(data)
db.session.commit()
return {"message": "Limit of group was changed!"}

View File

@ -1,13 +1,12 @@
from random import randint from random import randint
from itertools import islice from itertools import islice
from typing import List
from flask import Response, abort from flask import Response, abort
from apiflask import APIBlueprint from apiflask import APIBlueprint
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from flask_sqlalchemy import get_debug_queries from flask_sqlalchemy import get_debug_queries
from ...students.models import Student, Group from ...students.models import Student, Group, YearGroup, YearGroupStudents
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, \ from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, \
StudentCreateSchema, MessageSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema StudentCreateSchema, MessageSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema
@ -19,19 +18,19 @@ from ...base.utils import paginate_models, is_allowed_extensions
bp = APIBlueprint("students", __name__, url_prefix="/students") bp = APIBlueprint("students", __name__, url_prefix="/students")
@bp.route("/", methods=["GET"]) @bp.get("/<int:year_group_id>/")
@bp.input(StudentQuerySchema, location='query') @bp.input(StudentQuerySchema, location='query')
@bp.output(StudentsPaginationSchema) @bp.output(StudentsPaginationSchema)
def list_students(query: dict) -> dict: def list_students(year_group_id: int, query: dict) -> dict:
# add filter by year group
fullname = query.get('fullname') fullname = query.get('fullname')
order_by_first_name = query.get('order_by_first_name') order_by_first_name = query.get('order_by_first_name')
order_by_last_name = query.get('order_by_last_name') order_by_last_name = query.get('order_by_last_name')
mode = query.get('mode')
page = query.get('page') page = query.get('page')
per_page = query.get('per_page') per_page = query.get('per_page')
student_query = Student.search_by_fullname_and_mode_and_order_by_first_name_or_last_name( student_query = Student.search_by_fullname_and_mode_and_order_by_first_name_or_last_name(
fullname, mode, order_by_first_name, order_by_last_name) year_group_id, fullname, order_by_first_name, order_by_last_name)
data = paginate_models(page, student_query, per_page) data = paginate_models(page, student_query, per_page)
# print(get_debug_queries()[0]) # print(get_debug_queries()[0])
@ -41,7 +40,7 @@ def list_students(query: dict) -> dict:
} }
@bp.route("/<int:index>/", methods=["GET"]) @bp.get("/<int:index>/")
@bp.output(StudentSchema) @bp.output(StudentSchema)
def detail_student(index: int) -> Student: def detail_student(index: int) -> Student:
student = Student.query.filter_by(index=index).first() student = Student.query.filter_by(index=index).first()
@ -50,7 +49,7 @@ def detail_student(index: int) -> Student:
return student return student
@bp.route("/<int:index>/", methods=["DELETE"]) @bp.delete("/<int:index>/")
@bp.output(MessageSchema, status_code=202) @bp.output(MessageSchema, status_code=202)
def delete_student(index: int) -> dict: def delete_student(index: int) -> dict:
student = Student.query.filter_by(index=index).first() student = Student.query.filter_by(index=index).first()
@ -61,7 +60,7 @@ def delete_student(index: int) -> dict:
return {"message": "Student was deleted!"} return {"message": "Student was deleted!"}
@bp.route("/<int:index>/", methods=["PUT"]) @bp.put("/<int:index>/")
@bp.input(StudentEditSchema) @bp.input(StudentEditSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def edit_student(index: int, data: dict) -> dict: def edit_student(index: int, data: dict) -> dict:
@ -80,11 +79,13 @@ def edit_student(index: int, data: dict) -> dict:
return {"message": "Student was updated!"} return {"message": "Student was updated!"}
@bp.route("/", methods=["POST"]) @bp.post("/")
@bp.input(StudentCreateSchema) @bp.input(StudentCreateSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def create_student(data: dict) -> dict: def create_student(data: dict) -> dict:
index = data['index'] index = data['index']
yg_id = data['year_group_id']
del data['year_group_id']
student = Student.query.filter_by(index=index).first() student = Student.query.filter_by(index=index).first()
if student is not None: if student is not None:
abort(400, "Student has already exists!") abort(400, "Student has already exists!")
@ -92,12 +93,20 @@ def create_student(data: dict) -> dict:
dummy_email = f'student{randint(1, 300_000)}@gmail.com' dummy_email = f'student{randint(1, 300_000)}@gmail.com'
student = Student(**data, email=dummy_email) student = Student(**data, email=dummy_email)
db.session.add(student) db.session.add(student)
# add student to the chosen year group
year_group = YearGroup.query.filter(YearGroup.id == yg_id).first()
if year_group is None:
abort(400, "Year group doesn't exist!")
ygs = YearGroupStudents(student_index=student.index, year_group_id=year_group.id)
db.session.add(ygs)
db.session.commit() db.session.commit()
return {"message": "Student was created!"} return {"message": "Student was created!"}
@bp.route("/upload/", methods=["POST"]) @bp.post("/upload/")
@bp.input(FileSchema, location='form_and_files') @bp.input(FileSchema, location='form_and_files')
@bp.output(MessageSchema) @bp.output(MessageSchema)
def upload_students(file: dict) -> dict: def upload_students(file: dict) -> dict:
@ -125,7 +134,7 @@ def upload_students(file: dict) -> dict:
return {"message": "Students was created by uploading csv file!"} return {"message": "Students was created by uploading csv file!"}
@bp.route("/download/", methods=["POST"]) @bp.post("/download/")
@bp.input(StudentListFileDownloaderSchema, location='query') @bp.input(StudentListFileDownloaderSchema, location='query')
def download_students(query: dict) -> Response: def download_students(query: dict) -> Response:
mode = query.get('mode') mode = query.get('mode')

View File

@ -0,0 +1,72 @@
from flask import abort
from apiflask import APIBlueprint
from flask_sqlalchemy import get_debug_queries
from ...students.models import YearGroup
from ..schemas import YearGroupSchema, MessageSchema, YearGroupPaginationSchema, YearGroupQuerySchema
from ...dependencies import db
from ...base.utils import paginate_models
bp = APIBlueprint("year_group", __name__, url_prefix="/year-group")
@bp.post('/')
@bp.input(YearGroupSchema)
@bp.output(MessageSchema, status_code=200)
def create_year_group(data: dict) -> dict:
name = data['name']
year_group = YearGroup.query.filter(YearGroup.name == name).first()
if year_group is not None:
abort(400, "Year group has already exists!")
yg = YearGroup(**data)
db.session.add(yg)
db.session.commit()
return {"message": "Year group was created!"}
@bp.get('/')
@bp.input(YearGroupQuerySchema, location='query')
@bp.output(YearGroupPaginationSchema)
def list_of_year_groups(query: dict) -> dict:
page = query.get('page')
per_page = query.get('per_page')
year_group_query = YearGroup.query.order_by(db.desc(YearGroup.created_at))
data = paginate_models(page, year_group_query, per_page)
return {
"year_groups": data['items'],
"max_pages": data['max_pages']
}
@bp.put('/<int:id>/')
@bp.input(YearGroupSchema)
@bp.output(MessageSchema)
def update_year_of_group(id: int, data: dict) -> dict:
if not data:
abort(400, 'You have passed empty data!')
year_group_query = YearGroup.query.filter(YearGroup.id == id)
year_group = year_group_query.first()
if year_group is None:
abort(404, 'Not found year group!')
year_group_query.update(data)
db.session.commit()
return {"message": "Year group was updated!"}
@bp.delete('/<int:id>/')
@bp.output(MessageSchema, status_code=202)
def delete_year_of_group(id: int) -> dict:
year_group = YearGroup.query.filter_by(id=id).first()
if year_group is None:
abort(404, f"Year group doesn't exist!")
db.session.delete(year_group)
db.session.commit()
return {"message": "Year group was deleted!"}

View File

@ -3,7 +3,8 @@ from .examination_schedule import ExaminationScheduleSchema, ExaminationSchedule
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema
from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \ from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema, ProjectSupervisorYearGroupSchema
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \ from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \ StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \
StudentQuerySchema StudentQuerySchema
from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema

View File

@ -5,20 +5,22 @@ from ..validators import validate_datetime_greater_than_now
class ExaminationScheduleSchema(Schema): class ExaminationScheduleSchema(Schema):
title = fields.Str(validate=validate.Length(min=1, max=100), required=True) title = fields.Str(validate=validate.Length(min=1, max=100), required=True)
mode = fields.Boolean(required=True) start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
class ExaminationScheduleUpdateSchema(Schema): class ExaminationScheduleUpdateSchema(Schema):
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True) start_date_for_enrollment_students = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True) end_date_for_enrollment_students = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
class ExaminationScheduleListItemSchema(Schema): class ExaminationScheduleListItemSchema(Schema):
id = fields.Integer(required=True) id = fields.Integer()
title = fields.Str(validate=validate.Length(min=1, max=100), required=True) title = fields.Str()
mode = fields.Boolean(required=True) start_date = fields.DateTime()
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True) end_date = fields.DateTime()
end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True) start_date_for_enrollment_students = fields.DateTime()
end_date_for_enrollment_students = fields.DateTime()
class ExaminationSchedulesPaginationSchema(Schema): class ExaminationSchedulesPaginationSchema(Schema):
@ -32,7 +34,7 @@ class ExaminationSchedulesQuerySchema(Schema):
class ProjectSupervisorStatisticsSchema(Schema): class ProjectSupervisorStatisticsSchema(Schema):
full_name = fields.Str() fullname = fields.Str()
assigned_to_committee = fields.Integer() assigned_to_committee = fields.Integer()
groups_assigned_to_his_committee = fields.Integer() groups_assigned_to_his_committee = fields.Integer()

View File

@ -1,36 +1,32 @@
from marshmallow import fields, validate from marshmallow import fields, validate, Schema
from ...dependencies import ma
from ..validators import validate_index
from .students import ProjectSupervisorSchema from .students import ProjectSupervisorSchema
class ProjectSupervisorQuerySchema(ma.Schema): class ProjectSupervisorQuerySchema(Schema):
fullname = fields.Str() fullname = fields.Str()
order_by_first_name = fields.Str() order_by_first_name = fields.Str()
order_by_last_name = fields.Str() order_by_last_name = fields.Str()
page = fields.Integer() page = fields.Integer()
per_page = fields.Integer() per_page = fields.Integer()
mode = fields.Integer()
class ProjectSupervisorsPaginationSchema(ma.Schema): class ProjectSupervisorsPaginationSchema(Schema):
project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema)) project_supervisors = fields.List(fields.Nested(ProjectSupervisorSchema))
max_pages = fields.Integer() max_pages = fields.Integer()
class ProjectSupervisorCreateSchema(ma.Schema): class ProjectSupervisorCreateSchema(Schema):
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True) first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True) last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
email = fields.Str(validate=validate.Length(min=1, max=255), required=True) email = fields.Str(validate=validate.Length(min=1, max=255), required=True)
limit_group = fields.Integer()
mode = fields.Integer(required=True)
class ProjectSupervisorEditSchema(ma.Schema): class ProjectSupervisorEditSchema(Schema):
first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True) first_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True) last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
email = fields.Str(validate=validate.Length(min=0, max=11), required=True) email = fields.Str(validate=validate.Length(min=0, max=11), required=True)
limit_group = fields.Integer(validate=validate_index)
count_groups = fields.Integer(validate=validate_index)
mode = fields.Integer(required=True) class ProjectSupervisorYearGroupSchema(Schema):
limit_group = fields.Integer(required=True)

View File

@ -40,7 +40,7 @@ class StudentCreateSchema(ma.Schema):
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True) last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
pesel = fields.Str(validate=validate.Length(min=0, max=11), required=True) pesel = fields.Str(validate=validate.Length(min=0, max=11), required=True)
index = fields.Integer(validate=validate_index, required=True) index = fields.Integer(validate=validate_index, required=True)
mode = fields.Boolean(required=True) year_group_id = fields.Integer()
class StudentEditSchema(ma.Schema): class StudentEditSchema(ma.Schema):
@ -48,7 +48,6 @@ class StudentEditSchema(ma.Schema):
last_name = fields.Str(validate=validate.Length(min=1, max=255)) last_name = fields.Str(validate=validate.Length(min=1, max=255))
pesel = fields.Str(validate=validate.Length(min=0, max=11)) pesel = fields.Str(validate=validate.Length(min=0, max=11))
index = fields.Integer(validate=validate_index) index = fields.Integer(validate=validate_index)
mode = fields.Boolean()
class MessageSchema(ma.Schema): class MessageSchema(ma.Schema):
@ -65,4 +64,3 @@ class StudentQuerySchema(ma.Schema):
order_by_last_name = fields.Str() order_by_last_name = fields.Str()
page = fields.Integer() page = fields.Integer()
per_page = fields.Integer() per_page = fields.Integer()
mode = fields.Boolean()

View File

@ -0,0 +1,30 @@
from marshmallow import Schema, fields, validate, ValidationError
from ...base.mode import ModeGroups
def validate_mode(value: str) -> str:
if value not in [m.value for m in ModeGroups]:
raise ValidationError("Invalid mode!")
return value
class YearGroupSchema(Schema):
name = fields.Str(validate=validate.Regexp('^\d{4}/\d{4}$'), required=True)
mode = fields.Str(validate=validate_mode, required=True)
class YearGroupItemSchema(Schema):
id = fields.Integer()
name = fields.Str()
mode = fields.Str()
class YearGroupPaginationSchema(Schema):
year_groups = fields.List(fields.Nested(YearGroupItemSchema))
max_pages = fields.Integer()
class YearGroupQuerySchema(Schema):
page = fields.Integer()
per_page = fields.Integer()

View File

@ -13,7 +13,7 @@ from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Table
from .exceptions import InvalidNameOrTypeHeaderException from .exceptions import InvalidNameOrTypeHeaderException
from ..students.models import Student from ..students.models import Student
from ..examination_schedule.models import Enrollment # from ..examination_schedule.models import Enrollment
def check_columns(df: pd.DataFrame) -> bool: def check_columns(df: pd.DataFrame) -> bool:
@ -66,7 +66,7 @@ def generate_csv(students: List[Student]) -> str:
return df.to_csv(index=False) return df.to_csv(index=False)
def generate_examination_schedule_pdf_file(title: str, nested_enrollments: List[List[Enrollment]]) -> bytes: def generate_examination_schedule_pdf_file(title: str, nested_enrollments: List[List[object]]) -> bytes:
pagesize = (297 * mm, 210 * mm) pagesize = (297 * mm, 210 * mm)
headers = ["lp.", "Godzina", "Nazwa projektu", "Opiekun", "Zespol", "Komisja"] headers = ["lp.", "Godzina", "Nazwa projektu", "Opiekun", "Zespol", "Komisja"]
pdf_buffer = BytesIO() pdf_buffer = BytesIO()

View File

@ -6,33 +6,40 @@ class ExaminationSchedule(Base):
__tablename__ = 'examination_schedules' __tablename__ = 'examination_schedules'
title = db.Column(db.String(100), unique=True, nullable=False) title = db.Column(db.String(100), unique=True, nullable=False)
mode = db.Column(db.Boolean, default=True, nullable=False) # True - stationary, False - non-stationary duration_time = db.Column(db.Integer) # in minutes
start_date = db.Column(db.DateTime) start_date_for_enrollment_students = db.Column(db.DateTime)
end_date = db.Column(db.DateTime) end_date_for_enrollment_students = db.Column(db.DateTime)
start_date = db.Column(db.DateTime, nullable=False)
end_date = db.Column(db.DateTime, nullable=False)
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'), nullable=False)
year_group = db.relationship('YearGroup', backref='examination_schedules')
class Enrollment(Base): committee = db.Table(
__tablename__ = 'enrollments' "committees",
db.Column("term_of_defence_id", db.ForeignKey("term_of_defences.id")),
db.Column("project_supervisor_id", db.ForeignKey("project_supervisors.id")),
)
class TermOfDefence(Base):
__tablename__ = 'term_of_defences'
start_date = db.Column(db.DateTime, nullable=False) start_date = db.Column(db.DateTime, nullable=False)
end_date = db.Column(db.DateTime, nullable=False) end_date = db.Column(db.DateTime, nullable=False)
examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id')) examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id'))
examination_schedule = db.relationship('ExaminationSchedule', backref='enrollments') examination_schedule = db.relationship('ExaminationSchedule', backref='term_of_defences')
committee = db.relationship("Committee", uselist=False, backref=db.backref('enrollment', passive_deletes=True))
group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
group = db.relationship("Group", uselist=False, backref='enrollment') group = db.relationship("Group", uselist=False, backref='term_of_defence')
members_of_committee = db.relationship("ProjectSupervisor", secondary=committee)
class Committee(Base): class TemporaryAvailability(Base):
__tablename__ = 'committees' __tablename__ = 'temporary_availabilities'
enrollment_id = db.Column(db.Integer, db.ForeignKey('enrollments.id', ondelete='CASCADE')) start_date = db.Column(db.DateTime, nullable=False)
members = db.relationship('ProjectSupervisor', secondary='committees_projects_supervisors', backref='committees') end_date = db.Column(db.DateTime, nullable=False)
examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id'), nullable=False)
examination_schedule = db.relationship("ExaminationSchedule", backref='temporary_availabilities')
class CommitteeProjectSupervisor(Base): project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'), nullable=False)
__tablename__ = 'committees_projects_supervisors' project_supervisor = db.relationship("ProjectSupervisor", backref='temporary_availabilities')
chairman = db.Column(db.Boolean, default=False, nullable=False)
committee_id = db.Column(db.Integer, db.ForeignKey('committees.id'))
member_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'))

View File

@ -1,9 +1,3 @@
from flask import Blueprint from flask import Blueprint
from .enrollments import bp as enrollments_bp
from .examination_schedule import bp as examination_schedule_bp
bp = Blueprint("examination_schedule", __name__, url_prefix="/examination_schedule") bp = Blueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
bp.register_blueprint(enrollments_bp)
bp.register_blueprint(examination_schedule_bp)

View File

@ -3,7 +3,7 @@ import datetime
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask import abort from flask import abort
from ..schemas import EnrollmentPaginationSchema, EnrollmentQuerySchema from ..schemas import EnrollmentPaginationSchema, EnrollmentQuerySchema, ExaminationScheduleProjectSupervisorViewSchema
from ..utils import check_examination_schedule_is_exist, get_list_of_enrollments_response from ..utils import check_examination_schedule_is_exist, get_list_of_enrollments_response
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
@ -33,29 +33,7 @@ def list_enrollments_for_students(examination_schedule_id: int, query: dict) ->
@bp.get('/<int:examination_schedule_id>/coordinator-view/') @bp.get('/<int:examination_schedule_id>/coordinator-view/')
@bp.input(EnrollmentQuerySchema, location='query') @bp.output(ExaminationScheduleProjectSupervisorViewSchema)
@bp.output(EnrollmentPaginationSchema) def list_enrollments_for_coordinator(examination_schedule_id: int) -> dict:
def list_enrollments_for_coordinator(examination_schedule_id: int, query: dict) -> dict: return check_examination_schedule_is_exist(examination_schedule_id)
page = query.get('page')
per_page = query.get('per_page')
check_examination_schedule_is_exist(examination_schedule_id)
return get_list_of_enrollments_response(examination_schedule_id, page, per_page)
@bp.get('/<int:examination_schedule_id>/project-supervisor-view/')
@bp.input(EnrollmentQuerySchema, location='query')
@bp.output(EnrollmentPaginationSchema)
def list_enrollments_for_project_supervisor(examination_schedule_id: int, query: dict) -> dict:
page = query.get('page')
per_page = query.get('per_page')
examination_schedule = check_examination_schedule_is_exist(examination_schedule_id)
now = datetime.datetime.utcnow()
if examination_schedule.start_date.timestamp() < now.timestamp():
abort(403, "Forbidden! Enrollment has just started! You cannot assign to the exam committees!")
return get_list_of_enrollments_response(examination_schedule_id, page, per_page)

View File

@ -1,32 +1,18 @@
import datetime import datetime
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask import abort
from ...dependencies import db from ...dependencies import db
from ..models import ExaminationSchedule from ..models import ExaminationSchedule
from ..schemas import ExaminationScheduleListSchema
bp = APIBlueprint("list_of_examination_schedule", __name__, url_prefix="/") bp = APIBlueprint("list_of_examination_schedule", __name__, url_prefix="/")
@bp.get('/project-supervisor-view/')
@bp.output(ExaminationScheduleListSchema)
def list_examination_schedule_for_project_supervisors() -> dict:
now = datetime.datetime.utcnow()
examination_schedules = db.session.query(ExaminationSchedule). \
filter(ExaminationSchedule.start_date > now). \
all()
return {'examination_schedules': examination_schedules}
@bp.get('/students-view/') @bp.get('/students-view/')
@bp.output(ExaminationScheduleListSchema)
def list_examination_schedule_for_students() -> dict: def list_examination_schedule_for_students() -> dict:
# in the future filter after the mode of examination schedule if we will have authorization module # in the future filter after the mode of examination schedule if we will have authorization module
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()
examination_schedules = db.session.query(ExaminationSchedule).\ examination_schedules = db.session.query(ExaminationSchedule).\
filter(ExaminationSchedule.start_date < now).\ filter(ExaminationSchedule.start_date_for_enrollment_students < now).\
filter(ExaminationSchedule.end_date > now).\ filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
all()
return {'examination_schedules': examination_schedules} return {'examination_schedules': examination_schedules}

View File

@ -27,15 +27,13 @@ class EnrollmentPaginationSchema(Schema):
max_pages = fields.Integer() max_pages = fields.Integer()
class ExaminationScheduleProjectSupervisorViewSchema(Schema):
id = fields.Integer()
start_date = fields.DateTime()
end_date = fields.DateTime()
class EnrollmentQuerySchema(Schema): class EnrollmentQuerySchema(Schema):
page = fields.Integer() page = fields.Integer()
per_page = fields.Integer() per_page = fields.Integer()
class ExaminationScheduleSchema(Schema):
id = fields.Integer()
title = fields.Str()
class ExaminationScheduleListSchema(Schema):
examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema))

View File

@ -1,7 +1,7 @@
from flask import abort from flask import abort
from ..dependencies import db from ..dependencies import db
from .models import Enrollment, Committee, ExaminationSchedule from .models import ExaminationSchedule
from ..students.models import Group from ..students.models import Group
from ..base.utils import paginate_models from ..base.utils import paginate_models

View File

@ -3,24 +3,31 @@ from flask_sqlalchemy import BaseQuery
from ..dependencies import db from ..dependencies import db
from ..base.models import Person, Base from ..base.models import Person, Base
from ..base.utils import order_by_column_name from ..base.utils import order_by_column_name
from ..students.models import YearGroup
class YearGroupProjectSupervisors(Base):
__tablename__ = 'year_group_project_supervisors'
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'), nullable=False)
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'), nullable=False)
limit_group = db.Column(db.Integer, default=3, nullable=False)
class ProjectSupervisor(Base, Person): class ProjectSupervisor(Base, Person):
__tablename__ = "project_supervisors" __tablename__ = "project_supervisors"
limit_group = db.Column(db.Integer, default=3, nullable=False) year_groups = db.relationship('YearGroupProjectSupervisors', lazy=True)
count_groups = db.Column(db.Integer, default=0, nullable=False)
mode = db.Column(db.Integer, default=0, nullable=False) # 0 - stationary, 1 - non-stationary, 2 - both
@classmethod @classmethod
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, fullname: str = None, def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int = None,
mode: int = None, fullname: str = None,
order_by_first_name: str = None, order_by_first_name: str = None,
order_by_last_name: str = None) -> BaseQuery: order_by_last_name: str = None) -> BaseQuery:
project_supervisors_query = cls.query project_supervisors_query = cls.query
if mode is not None: if year_group_id is not None:
project_supervisors_query = project_supervisors_query.filter(mode != 1 - mode) project_supervisors_query = project_supervisors_query.filter(YearGroup.id == year_group_id)
if fullname is not None: if fullname is not None:
project_supervisors_query = project_supervisors_query.filter( project_supervisors_query = project_supervisors_query.filter(

View File

@ -3,11 +3,11 @@ import datetime
from flask import abort from flask import abort
from ..dependencies import db from ..dependencies import db
from ..examination_schedule.models import Enrollment, ExaminationSchedule, Committee from ..examination_schedule.models import ExaminationSchedule
def get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id: int, def get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id: int,
enrollment_id: int) -> Enrollment: enrollment_id: int) -> None:
enrollment = db.session.query(Enrollment). \ enrollment = db.session.query(Enrollment). \
join(ExaminationSchedule, isouter=True).join(Committee, isouter=True). \ join(ExaminationSchedule, isouter=True).join(Committee, isouter=True). \
filter(ExaminationSchedule.id == examination_schedule_id). \ filter(ExaminationSchedule.id == examination_schedule_id). \
@ -20,12 +20,6 @@ def get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedu
return enrollment return enrollment
def check_the_project_supervisor_is_in_committee(enrollment_id: int, project_supervisor_id) -> bool:
return db.session.query(
Committee.query.join(Committee.members).filter(Committee.enrollment_id == enrollment_id).filter(
Committee.members.any(id=project_supervisor_id)).exists()).scalar()
def check_the_enrollments_has_just_started(start_date: datetime.datetime, action: str) -> None: def check_the_enrollments_has_just_started(start_date: datetime.datetime, action: str) -> None:
now = datetime.datetime.utcnow() now = datetime.datetime.utcnow()

View File

@ -1,20 +1,21 @@
from apiflask import APIBlueprint from datetime import datetime
from flask import abort, current_app
from ..schemas import MessageSchema, CommitteeCreateSchema, TemporaryProjectSupervisorSchema from apiflask import APIBlueprint
from ...examination_schedule.models import Committee from flask import abort
from ..schemas import MessageSchema, TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
ListOfFreeTimesSchema
from ...dependencies import db from ...dependencies import db
from ..models import ProjectSupervisor from ..models import ProjectSupervisor
from ..query import get_enrollment_by_enrollment_and_examination_schedule_ids, \ from ...examination_schedule.models import ExaminationSchedule, TemporaryAvailability, TermOfDefence
check_the_project_supervisor_is_in_committee, check_the_enrollments_has_just_started
bp = APIBlueprint("enrollments", __name__, url_prefix="/") bp = APIBlueprint("enrollments", __name__, url_prefix="/")
@bp.post('/<int:examination_schedule_id>/enrollments/<int:enrollment_id>/') @bp.post('/<int:examination_schedule_id>/enrollments/')
@bp.input(CommitteeCreateSchema) @bp.input(TimeAvailabilityCreateSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def assign_yourself_to_committee(examination_schedule_id: int, enrollment_id: int, data: dict) -> dict: def set_your_free_time_to_examination_schedule(examination_schedule_id: int, data: dict) -> dict:
# this code will be removed # this code will be removed
project_supervisor = db.session.query(ProjectSupervisor).filter( project_supervisor = db.session.query(ProjectSupervisor).filter(
ProjectSupervisor.id == data['project_supervisor_id']).first() ProjectSupervisor.id == data['project_supervisor_id']).first()
@ -22,43 +23,100 @@ def assign_yourself_to_committee(examination_schedule_id: int, enrollment_id: in
abort(404, "ProjectSupervisor doesn't exist!") abort(404, "ProjectSupervisor doesn't exist!")
################ ################
limit_of_committtee = current_app.config['LIMIT_PERSONS_PER_COMMITTEE'] es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
if es is None:
abort(404, "Examination schedule doesn't exist!")
enrollment = get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id, enrollment_id) sd = data['start_date']
check_the_enrollments_has_just_started(enrollment.examination_schedule.start_date, "assign") ed = data['end_date']
if sd > ed:
abort(400, "Invalid data! End date must be greater than start date!")
size_of_committee = db.session.query(Committee).join(Committee.members). \ if not (es.start_date >= sd and es.end_date <= ed):
filter(Committee.enrollment_id == enrollment.id).count() abort(400, "Invalid date ranges!")
if size_of_committee >= limit_of_committtee: now = datetime.utcnow()
abort(400, "The committee is full!") if es.start_date_for_enrollment_students is not None and \
es.start_date_for_enrollment_students.timestamp() < now.timestamp():
abort(403, "Enrollment has started! You cannot set your free time!")
if check_the_project_supervisor_is_in_committee(enrollment.id, project_supervisor.id): ta_query = TemporaryAvailability.query.filter(
abort(400, "You have already in this committee!") TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
filter(TemporaryAvailability.project_supervisor_id == project_supervisor.id)
if ta_query.first() is not None:
# implement logic
pass
enrollment.committee.members.append(project_supervisor) ta = TemporaryAvailability(**data, examination_schedule_id=examination_schedule_id,
db.session.add(enrollment) project_supervisor_id=project_supervisor.id)
db.session.add(ta)
db.session.commit() db.session.commit()
return {"message": "You have just assigned yourself to committee!"} return {"message": "You have just assigned your free time!"}
@bp.delete('/<int:examination_schedule_id>/enrollments/<int:enrollment_id>/') @bp.delete('/<int:examination_schedule_id>/enrollments/<int:id>/')
@bp.input(TemporaryProjectSupervisorSchema) @bp.input(TemporaryProjectSupervisorSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def delete_yourself_from_committee(examination_schedule_id: int, enrollment_id: int, data: dict) -> dict: def delete_your_free_time_from_examination_schedule(examination_schedule_id: int, id: int, data: dict) -> dict:
# this code will be removed # this code will be removed
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first() project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
if project_supervisor is None: if project_supervisor is None:
abort(404, "ProjectSupervisor doesn't exist!") abort(404, "ProjectSupervisor doesn't exist!")
################ ################
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
TemporaryAvailability.project_supervisor_id == project_supervisor.id,
TemporaryAvailability.id == id).first()
enrollment = get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id, enrollment_id) if ta is None:
check_the_enrollments_has_just_started(enrollment.examination_schedule.start_date, "delete") abort(404, "Your free time doesn't exist!")
if not check_the_project_supervisor_is_in_committee(enrollment.id, project_supervisor.id): db.session.delete(ta)
abort(400, "You are not assigned to this committee!")
enrollment.committee.members.remove(project_supervisor)
db.session.commit() db.session.commit()
return {"message": "You have just removed from committee!"} return {"message": "You have just removed your free time!"}
@bp.get('/<int:examination_schedule_id>/')
@bp.input(TemporaryProjectSupervisorSchema, location='query')
@bp.output(ListOfFreeTimesSchema)
def list_enrollments_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict:
# this code will be removed
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
if project_supervisor is None:
abort(404, "ProjectSupervisor doesn't exist!")
################
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
ExaminationSchedule.year_group_id).first()
if es is None:
abort(404, "Examination schedule doesn't exist!")
now = datetime.utcnow()
if es.start_date_for_enrollment_students.timestamp() < now.timestamp():
abort(403, "Forbidden! Enrollment has just started! You cannot assign to the exam committees!")
# list of your term of defences first enrollment
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
TemporaryAvailability.project_supervisor_id == project_supervisor.id).all()
return ta
@bp.get('/<int:examination_schedule_id>/term-of-defences/')
@bp.input(TemporaryProjectSupervisorSchema, location='query')
@bp.output(ListOfFreeTimesSchema)
def list_created_enrollment_by_coordinator_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict:
# this code will be removed
project_supervisor = db.session.query(ProjectSupervisor).filter(ProjectSupervisor.id == data['id']).first()
if project_supervisor is None:
abort(404, "ProjectSupervisor doesn't exist!")
################
es = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id,
ExaminationSchedule.year_group_id).first()
if es is None:
abort(404, "Examination schedule doesn't exist!")
# list of your free times first enrollment
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
filter_by(project_supervisor_id=project_supervisor.id).all()
return td

View File

@ -1,13 +1,23 @@
from marshmallow import fields, validate, Schema from marshmallow import fields, validate, Schema
# MessageSchema, CommitteeCreateSchema
class MessageSchema(Schema): class MessageSchema(Schema):
message = fields.Str() message = fields.Str()
class CommitteeCreateSchema(Schema): class FreeTimeSchema(Schema):
id = fields.Integer()
start_date = fields.DateTime(required=True)
end_date = fields.DateTime(required=True)
class ListOfFreeTimesSchema(Schema):
free_times = fields.List(fields.Nested(FreeTimeSchema))
class TimeAvailabilityCreateSchema(Schema):
start_date = fields.DateTime(required=True)
end_date = fields.DateTime(required=True)
project_supervisor_id = fields.Integer(required=True) # temporary field it will be removed in the future project_supervisor_id = fields.Integer(required=True) # temporary field it will be removed in the future

View File

@ -1,9 +1,27 @@
from datetime import datetime
from flask_sqlalchemy import BaseQuery from flask_sqlalchemy import BaseQuery
from ..dependencies import db from ..dependencies import db
from ..base.models import Person, Base from ..base.models import Person, Base
from ..base.utils import order_by_column_name from ..base.utils import order_by_column_name
from ..examination_schedule.models import Enrollment from ..examination_schedule.models import TermOfDefence
class YearGroupStudents(Base):
__tablename__ = 'year_group_students'
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id', ondelete='CASCADE'))
student_index = db.Column(db.Integer, db.ForeignKey('students.index', ondelete='CASCADE'))
class YearGroup(Base):
__tablename__ = 'year_groups'
name = db.Column(db.String(50), unique=True, nullable=False)
mode = db.Column(db.String(1), unique=True, nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
students = db.relationship("YearGroupStudents")
class Group(Base): class Group(Base):
@ -15,13 +33,14 @@ class Group(Base):
tzaj_kod = db.Column(db.String(60), default='LAB') tzaj_kod = db.Column(db.String(60), default='LAB')
project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id')) project_supervisor_id = db.Column(db.Integer, db.ForeignKey('project_supervisors.id'))
project_supervisor = db.relationship('ProjectSupervisor', backref='groups', lazy=True) project_supervisor = db.relationship('ProjectSupervisor', backref='groups', lazy=True)
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
year_group = db.relationship('YearGroup', backref='groups', lazy=True)
points_for_first_term = db.Column(db.Integer, default=0, nullable=False) points_for_first_term = db.Column(db.Integer, default=0, nullable=False)
points_for_second_term = db.Column(db.Integer, default=0, nullable=False) points_for_second_term = db.Column(db.Integer, default=0, nullable=False)
# enrollment = db.relationship('Enrollment', uselist=False, backref='group')
@classmethod @classmethod
def search_by_name(cls, search_name: str = None) -> BaseQuery: def search_by_name(cls, year_group_id: int, search_name: str = None) -> BaseQuery:
group_query = cls.query group_query = cls.query.filter(Group.year_group_id == year_group_id)
if search_name is not None: if search_name is not None:
group_query = group_query.filter(Group.name.like(f'{search_name}%')) group_query = group_query.filter(Group.name.like(f'{search_name}%'))
@ -35,18 +54,14 @@ class Student(Person):
pesel = db.Column(db.String(11), default='') pesel = db.Column(db.String(11), default='')
index = db.Column(db.Integer, primary_key=True) index = db.Column(db.Integer, primary_key=True)
group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) group_id = db.Column(db.Integer, db.ForeignKey('groups.id'))
group = db.relationship('Group', backref='students', lazy=True) groups = db.relationship('Group', backref='students', lazy=True)
mode = db.Column(db.Boolean, default=True, nullable=False) # True - stationary, False - non-stationary year_groups = db.relationship("YearGroupStudents")
@classmethod @classmethod
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, fullname: str = None, def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int, fullname: str = None,
mode: bool = None,
order_by_first_name: str = None, order_by_first_name: str = None,
order_by_last_name: str = None) -> BaseQuery: order_by_last_name: str = None) -> BaseQuery:
student_query = cls.query student_query = cls.query.filter(YearGroup.id == year_group_id)
if mode is not None:
student_query = student_query.filter_by(mode=mode)
if fullname is not None: if fullname is not None:
student_query = student_query.filter((Student.first_name + ' ' + Student.last_name).like(f'{fullname}%')) student_query = student_query.filter((Student.first_name + ' ' + Student.last_name).like(f'{fullname}%'))

View File

@ -3,14 +3,11 @@ import datetime
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask import abort from flask import abort
from ..schemas import MessageSchema, TemporaryStudentSchema from ..schemas import MessageSchema, TemporaryStudentSchema, ExaminationScheduleListSchema
from ...dependencies import db from ...dependencies import db
from ...examination_schedule.models import Enrollment from ..models import Student, Group, TermOfDefence
from ..models import Student, Group from ...examination_schedule.models import ExaminationSchedule
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor
from ...project_supervisor.query import get_enrollment_by_enrollment_and_examination_schedule_ids, \
check_the_project_supervisor_is_in_committee
from ..query import check_the_enrollments_has_just_started
bp = APIBlueprint("enrollments", __name__, url_prefix="/") bp = APIBlueprint("enrollments", __name__, url_prefix="/")
@ -18,52 +15,93 @@ bp = APIBlueprint("enrollments", __name__, url_prefix="/")
@bp.post('/<int:examination_schedule_id>/enrollments/<int:enrollment_id>/') @bp.post('/<int:examination_schedule_id>/enrollments/<int:enrollment_id>/')
@bp.input(TemporaryStudentSchema) @bp.input(TemporaryStudentSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def assign_group_for_this_exam_date(examination_schedule_id: int, enrollment_id: int, data: dict) -> dict: def assign_your_group_to_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
# this code will be removed # this code will be removed
student = Student.query.filter(Student.index == data['student_index']).first() student = Student.query.filter(Student.index == data['student_index']).first()
if student is None: if student is None:
abort(404, "Student doesn't exist!") abort(404, "Student doesn't exist!")
################ ################
st = Student.query.join(Group).join(ProjectSupervisor).filter(Student.index == student.index).first() st = Student.query.join(Group).join(ProjectSupervisor).filter(Student.index == student.index).first()
enrollment = db.session.query(Enrollment.id).filter(Enrollment.group_id == st.group.id).first()
if enrollment is not None:
abort(400, "Your group has already assigned to any exam date!")
enrollment = get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id, enrollment_id)
check_the_enrollments_has_just_started(enrollment.examination_schedule)
if st is None or st.group.project_supervisor is None: if st is None or st.group.project_supervisor is None:
abort(400, "You don't have a group or your group doesn't have an assigned project supervisor!") abort(400, "You don't have a group or your group doesn't have an assigned project supervisor!")
if not check_the_project_supervisor_is_in_committee(enrollment_id, st.group.project_supervisor.id): defence = TermOfDefence.query.filter(TermOfDefence.group_id == st.group.id,
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
if defence is not None:
abort(400, "Your group has already assigned to any exam date!")
g = Group.query.filter(id=st.group_id).first()
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
filter_by(project_supervisor_id=g.project_supervisor_id).first()
if td is None:
abort(400, "Your project supervisor is not in committee!") abort(400, "Your project supervisor is not in committee!")
enrollment.group_id = st.group.id defence.group_id = st.group.id
db.session.add(enrollment) db.session.add(defence)
db.session.commit() db.session.commit()
return {"message": "You have just assigned the group for this exam date!"} return {"message": "You have just assigned the group for this exam date!"}
@bp.delete('/<int:examination_schedule_id>/enrollments/<int:enrollment_id>/') @bp.delete('/<int:examination_schedule_id>/enrollments/<int:term_of_defence_id>/')
@bp.input(TemporaryStudentSchema) @bp.input(TemporaryStudentSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def delete_group_for_this_exam_date(examination_schedule_id: int, enrollment_id: int, data: dict) -> dict: def delete_your_group_from_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
# this code will be removed # this code will be removed
student = Student.query.filter(Student.index == data['student_index']).first() student = Student.query.filter(Student.index == data['student_index']).first()
if student is None: if student is None:
abort(404, "Student doesn't exist!") abort(404, "Student doesn't exist!")
################ ################
enrollment = get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id, enrollment_id) term_of_defence = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id). \
filter(TermOfDefence.examination_schedule_id == examination_schedule_id).first()
if student.group.id != enrollment.group_id: if term_of_defence is None:
abort(400, "You are not assigned to this committee!") abort(404, "Term of defence doesn't exist!")
check_the_enrollments_has_just_started(enrollment.examination_schedule) if student.group.id != term_of_defence.group_id:
abort(400, "You are not assigned to this group!")
enrollment.group = None term_of_defence.group_id = None
db.session.add(enrollment) db.session.add(term_of_defence)
db.session.commit() db.session.commit()
return {"message": "You have just removed the group for this exam date!"} return {"message": "You have just removed the group for this exam date!"}
@bp.get('/examination-schedule/year-group/<int:year_group_id>/')
@bp.input(TemporaryStudentSchema)
@bp.output(ExaminationScheduleListSchema)
def list_examination_schedule_for_students(year_group_id: int, data: dict) -> dict:
# this code will be removed
student = Student.query.filter(Student.index == data['student_index']).first()
if student is None:
abort(404, "Student doesn't exist!")
################
# in the future filter after the mode of examination schedule if we will have authorization module
now = datetime.datetime.utcnow()
examination_schedules = ExaminationSchedule.query. \
filter(ExaminationSchedule.year_group_id == year_group_id). \
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
return {'examination_schedules': examination_schedules}
@bp.get('/enrollments/')
@bp.input(TemporaryStudentSchema)
@bp.output(ExaminationScheduleListSchema)
def list_term_of_defences_for_students(data: dict) -> dict:
# this code will be removed
student = Student.query.filter(Student.index == data['student_index']).first()
if student is None:
abort(404, "Student doesn't exist!")
################
# in the future filter after the mode of examination schedule if we will have authorization module
now = datetime.datetime.utcnow()
term_of_defences = TermOfDefence.query.join(ExaminationSchedule, isouter=True). \
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
filter(ExaminationSchedule.end_date_for_enrollment_students > now). \
filter(TermOfDefence.group_id == student.group_id). \
all()
return {'examination_schedules': term_of_defences}

View File

@ -1,6 +1,6 @@
from apiflask import APIBlueprint from apiflask import APIBlueprint
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
from ..models import Group from ..models import Group
from ...dependencies import db from ...dependencies import db
from ..schemas import ProjectSupervisorQuerySchema, ProjectSupervisorPaginationSchema from ..schemas import ProjectSupervisorQuerySchema, ProjectSupervisorPaginationSchema
@ -9,21 +9,20 @@ from ...base.utils import paginate_models
bp = APIBlueprint("registrations", __name__, url_prefix="/registrations") bp = APIBlueprint("registrations", __name__, url_prefix="/registrations")
@bp.get('/') @bp.get('/<int:year_group_id>/')
@bp.input(ProjectSupervisorQuerySchema, location='query') @bp.input(ProjectSupervisorQuerySchema, location='query')
@bp.output(ProjectSupervisorPaginationSchema) @bp.output(ProjectSupervisorPaginationSchema)
def list_available_groups(query: dict) -> dict: def list_available_groups(year_group_id: int, query: dict) -> dict:
mode = 0 if query.get('mode') else 1
page = query.get('page') page = query.get('page')
per_page = query.get('per_page') per_page = query.get('per_page')
available_groups = (ProjectSupervisor.limit_group - ProjectSupervisor.count_groups) available_groups = (YearGroupProjectSupervisors.limit_group - db.func.count(Group.id))
ps_query = db.session.query(ProjectSupervisor, available_groups).join(Group, isouter=True) ps_query = db.session. \
query(ProjectSupervisor, available_groups). \
if mode is not None: join(Group, isouter=True). \
ps_query = ps_query.filter(ProjectSupervisor.mode != 1-mode) join(YearGroupProjectSupervisors, isouter=True). \
filter(YearGroupProjectSupervisors.year_group_id == year_group_id).\
ps_query = ps_query.group_by(ProjectSupervisor.id) group_by(ProjectSupervisor.id)
data = paginate_models(page, ps_query, per_page) data = paginate_models(page, ps_query, per_page)

View File

@ -5,7 +5,6 @@ class ProjectSupervisorSchema(Schema):
first_name = fields.Str() first_name = fields.Str()
last_name = fields.Str() last_name = fields.Str()
email = fields.Str() email = fields.Str()
mode = fields.Integer()
available_groups = fields.Integer() available_groups = fields.Integer()
@ -17,7 +16,6 @@ class ProjectSupervisorPaginationSchema(Schema):
class ProjectSupervisorQuerySchema(Schema): class ProjectSupervisorQuerySchema(Schema):
page = fields.Integer() page = fields.Integer()
per_page = fields.Integer() per_page = fields.Integer()
mode = fields.Boolean()
class TemporaryStudentSchema(Schema): class TemporaryStudentSchema(Schema):
@ -26,3 +24,14 @@ class TemporaryStudentSchema(Schema):
class MessageSchema(Schema): class MessageSchema(Schema):
message = fields.Str() message = fields.Str()
class ExaminationScheduleSchema(Schema):
id = fields.Integer()
title = fields.Str()
start_date = fields.DateTime()
end_date = fields.DateTime()
class ExaminationScheduleListSchema(Schema):
examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema))

View File

@ -0,0 +1,28 @@
"""empty message
Revision ID: 5c3c4c4e1a72
Revises: a96f91e5b556
Create Date: 2022-11-12 11:48:38.377516
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '5c3c4c4e1a72'
down_revision = 'a96f91e5b556'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('examination_schedules', sa.Column('duration_time', sa.Integer(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('examination_schedules', 'duration_time')
# ### end Alembic commands ###

View File

@ -0,0 +1,141 @@
"""empty message
Revision ID: a96f91e5b556
Revises:
Create Date: 2022-11-12 11:34:01.223667
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'a96f91e5b556'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('project_supervisors',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('first_name', sa.String(length=255), nullable=False),
sa.Column('last_name', sa.String(length=255), nullable=False),
sa.Column('email', sa.String(length=120), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email')
)
op.create_index(op.f('ix_project_supervisors_first_name'), 'project_supervisors', ['first_name'], unique=False)
op.create_index(op.f('ix_project_supervisors_last_name'), 'project_supervisors', ['last_name'], unique=False)
op.create_table('year_groups',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('mode', sa.String(length=1), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('mode'),
sa.UniqueConstraint('name')
)
op.create_table('examination_schedules',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('title', sa.String(length=100), nullable=False),
sa.Column('year_group_id', sa.Integer(), nullable=False),
sa.Column('start_date_for_enrollment_students', sa.DateTime(), nullable=True),
sa.Column('end_date_for_enrollment_students', sa.DateTime(), nullable=True),
sa.Column('start_date', sa.DateTime(), nullable=False),
sa.Column('end_date', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('title')
)
op.create_table('groups',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=60), nullable=False),
sa.Column('cdyd_kod', sa.String(length=60), nullable=True),
sa.Column('prz_kod', sa.String(length=60), nullable=True),
sa.Column('tzaj_kod', sa.String(length=60), nullable=True),
sa.Column('project_supervisor_id', sa.Integer(), nullable=True),
sa.Column('year_group_id', sa.Integer(), nullable=True),
sa.Column('points_for_first_term', sa.Integer(), nullable=False),
sa.Column('points_for_second_term', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('year_group_project_supervisors',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('project_supervisor_id', sa.Integer(), nullable=False),
sa.Column('year_group_id', sa.Integer(), nullable=False),
sa.Column('limit_group', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('students',
sa.Column('first_name', sa.String(length=255), nullable=False),
sa.Column('last_name', sa.String(length=255), nullable=False),
sa.Column('email', sa.String(length=120), nullable=True),
sa.Column('pesel', sa.String(length=11), nullable=True),
sa.Column('index', sa.Integer(), nullable=False),
sa.Column('group_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
sa.PrimaryKeyConstraint('index'),
sa.UniqueConstraint('email')
)
op.create_index(op.f('ix_students_first_name'), 'students', ['first_name'], unique=False)
op.create_index(op.f('ix_students_last_name'), 'students', ['last_name'], unique=False)
op.create_table('temporary_availabilities',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('start_date', sa.DateTime(), nullable=False),
sa.Column('end_date', sa.DateTime(), nullable=False),
sa.Column('examination_schedule_id', sa.Integer(), nullable=False),
sa.Column('project_supervisor_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['examination_schedule_id'], ['examination_schedules.id'], ),
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('term_of_defences',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('start_date', sa.DateTime(), nullable=False),
sa.Column('end_date', sa.DateTime(), nullable=False),
sa.Column('examination_schedule_id', sa.Integer(), nullable=True),
sa.Column('group_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['examination_schedule_id'], ['examination_schedules.id'], ),
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('committees',
sa.Column('term_of_defence_id', sa.Integer(), nullable=True),
sa.Column('project_supervisor_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
sa.ForeignKeyConstraint(['term_of_defence_id'], ['term_of_defences.id'], )
)
op.create_table('year_group_students',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('year_group_id', sa.Integer(), nullable=True),
sa.Column('student_index', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['student_index'], ['students.index'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('year_group_students')
op.drop_table('committees')
op.drop_table('term_of_defences')
op.drop_table('temporary_availabilities')
op.drop_index(op.f('ix_students_last_name'), table_name='students')
op.drop_index(op.f('ix_students_first_name'), table_name='students')
op.drop_table('students')
op.drop_table('year_group_project_supervisors')
op.drop_table('groups')
op.drop_table('examination_schedules')
op.drop_table('year_groups')
op.drop_index(op.f('ix_project_supervisors_last_name'), table_name='project_supervisors')
op.drop_index(op.f('ix_project_supervisors_first_name'), table_name='project_supervisors')
op.drop_table('project_supervisors')
# ### end Alembic commands ###