update enrollments endpoints for coordinator, project supervisors and students

This commit is contained in:
dominik24c 2022-11-16 20:42:40 +01:00
parent eea98dd225
commit 856372e5ab
21 changed files with 314 additions and 253 deletions

View File

@ -23,8 +23,6 @@ class Config:
DESCRIPTION = 'System PRI' DESCRIPTION = 'System PRI'
OPENAPI_VERSION = '3.0.2' OPENAPI_VERSION = '3.0.2'
PROJECT_PRESENTATION_TIME = 30 # in minutes
class ProductionConfig(Config): class ProductionConfig(Config):
DB_SERVER = "0.0.0.0" DB_SERVER = "0.0.0.0"

View File

@ -1,7 +1,7 @@
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
@ -15,5 +15,5 @@ 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(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

@ -1,69 +1,174 @@
import datetime import datetime
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask import abort, current_app from flask import abort
from sqlalchemy import or_, and_
from ..schemas import MessageSchema, EnrollmentCreateSchema from ..schemas import MessageSchema, TermOfDefenceSchema, TermOfDefenceListSchema, \
from ...examination_schedule.models import ExaminationSchedule TemporaryAvailabilityListSchema
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence, TemporaryAvailability
from ...students.models import YearGroup
from ...project_supervisor.models import ProjectSupervisor
from ...dependencies import db from ...dependencies import db
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
@bp.post('/<int:examination_schedule_id>/') @bp.post('/<int:examination_schedule_id>/generate')
@bp.input(EnrollmentCreateSchema, location='json') def generate_term_of_defence_for_this_examination_schedule(examination_schedule_id: int) -> dict:
@bp.output(MessageSchema) pass
def create_enrollments(examination_schedule_id: int, data: dict) -> dict:
prt = current_app.config["PROJECT_PRESENTATION_TIME"]
examination_schedule = db.session.query(ExaminationSchedule).filter(
ExaminationSchedule.id == examination_schedule_id).first() @bp.post('/<int:examination_schedule_id>/add')
if examination_schedule is None: @bp.input(TermOfDefenceSchema)
abort(404, "Examination schedule doesn't exist!") @bp.output(MessageSchema)
def create_term_of_defence(examination_schedule_id: int, data: dict) -> dict:
if not data:
abort(400, "You have passed empty data!")
ex = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
if ex is None:
abort(404, "Not found examination schedule!")
yg_id = ex.year_group_id
project_supervisors_ids = data.pop('project_supervisors')
project_supervisors = ProjectSupervisor.query.filter(
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
if len(project_supervisors) != len(project_supervisors_ids):
abort(404, "Project Supervisors didn't exist!")
start_date = data['start_date'] start_date = data['start_date']
end_date = data['end_date'] end_date = data['end_date']
if start_date > end_date:
abort(400, "Invalid dates! End date must be greater than start date!")
if start_date.date() != end_date.date():
abort(400, "Invalid dates! Only hours can be different!")
enrollment = Enrollment.query.filter(Enrollment.start_date >= start_date, if not (ex.start_date.timestamp() < start_date.timestamp() and ex.end_date.timestamp() > end_date.timestamp()):
Enrollment.start_date < end_date).first() abort(400, "Invalid date range!")
if enrollment is not None:
abort(400, "You have just created enrollments for this range date!")
enrollment = Enrollment.query.filter(Enrollment.end_date > start_date, Enrollment.end_date <= end_date).first() if end_date <= start_date:
if enrollment is not None: abort(400, "End date must be greater than start date!")
abort(400, "You have just created enrollments for this range date! `1")
delta = end_date - start_date delta_time = end_date - start_date
delta_in_minutes = delta.total_seconds() / 60 delta_time_in_minutes = delta_time.total_seconds() / 60
if delta_in_minutes % prt != 0: if delta_time_in_minutes != ex.duration_time:
abort(400, "Invalid format dates!") abort(400, "Invalid duration time!")
amount = int(delta_in_minutes // prt) td = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
enrollments = [] filter(
for i in range(amount): or_(and_(TermOfDefence.start_date >= start_date,
sd = start_date + datetime.timedelta(minutes=i * prt) TermOfDefence.start_date < end_date,
ed = start_date + datetime.timedelta(minutes=(i + 1) * prt) TermOfDefence.end_date >= end_date),
enrollment = Enrollment(start_date=sd, end_date=ed, examination_schedule_id=examination_schedule_id) and_(TermOfDefence.start_date <= start_date,
enrollments.append(enrollment) TermOfDefence.end_date > start_date,
db.session.add_all(enrollments) TermOfDefence.end_date <= end_date))).first()
if td is not None:
abort(400, "This term of defence is taken! You choose other date!")
td = TermOfDefence(**data, examination_schedule_id=examination_schedule_id)
db.session.add(td)
db.session.commit() db.session.commit()
for p in project_supervisors:
committees = [Committee(enrollment_id=e.id) for e in enrollments] td.members_of_committee.append(p)
db.session.add_all(committees)
db.session.commit() db.session.commit()
return {"message": "Enrollments was created!"} return {"message": "Term of defence was created!"}
@bp.delete('/<int:enrollment_id>/') @bp.put('/<int:examination_schedule_id>/update/<int:term_of_defence_id>/')
@bp.input(TermOfDefenceSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def delete_enrollment(enrollment_id: int) -> dict: def update_term_of_defence(examination_schedule_id: int, term_of_defence_id: int, data: dict) -> dict:
enrollment = db.session.query(Enrollment).filter(Enrollment.id == enrollment_id).first() if not data:
if enrollment is None: abort(400, "You have passed empty data!")
abort(404, "Enrollment doesn't exist!")
db.session.delete(enrollment) td_query = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
TermOfDefence.examination_schedule_id == examination_schedule_id)
td = td_query.first()
if td is None:
abort(404, "Not found term of defence!")
ex = td.examination_schedule
yg_id = ex.year_group_id
project_supervisors_ids = data.pop('project_supervisors')
project_supervisors = ProjectSupervisor.query.filter(
or_(*[ProjectSupervisor.id == i for i in project_supervisors_ids])).filter(YearGroup.id == yg_id).all()
if len(project_supervisors) != len(project_supervisors_ids):
abort(404, "Project Supervisors didn't exist!")
start_date = data['start_date']
end_date = data['end_date']
if not (ex.start_date.timestamp() < start_date.timestamp() and ex.end_date.timestamp() > end_date.timestamp()):
abort(400, "Invalid date range!")
if end_date <= start_date:
abort(400, "End date must be greater than start date!")
delta_time = end_date - start_date
delta_time_in_minutes = delta_time.total_seconds() / 60
if delta_time_in_minutes != ex.duration_time:
abort(400, "Invalid duration time!")
term_of_defence = TermOfDefence.query.filter(TermOfDefence.id != term_of_defence_id,
TermOfDefence.examination_schedule_id == examination_schedule_id). \
filter(
or_(and_(TermOfDefence.start_date >= start_date,
TermOfDefence.start_date < end_date,
TermOfDefence.end_date >= end_date),
and_(TermOfDefence.start_date <= start_date,
TermOfDefence.end_date > start_date,
TermOfDefence.end_date <= end_date))).first()
if term_of_defence is not None:
abort(400, "This term of defence is taken! You choose other date!")
td_query.update(data)
td.members_of_committee = []
db.session.commit() db.session.commit()
return {"message": "Enrollment was deleted!"} for p in project_supervisors:
td.members_of_committee.append(p)
db.session.commit()
return {"message": "Term of defence was updated!"}
@bp.delete('/<int:examination_schedule_id>/delete/<int:term_of_defence_id>/')
@bp.output(MessageSchema)
def delete_term_of_defence(examination_schedule_id: int, term_of_defence_id: int) -> dict:
td = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
ExaminationSchedule.id == examination_schedule_id).first()
if td is None:
abort(404, "Not found term of defence!")
db.session.delete(td)
db.session.commit()
return {"message": "Term of defence was deleted!"}
@bp.get('/<int:examination_schedule_id>/term-of-defences/')
@bp.output(TermOfDefenceListSchema)
def list_of_term_of_defences(examination_schedule_id: int) -> dict:
ex = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
if ex is None:
abort(400, "Examination Schedule didn't exist")
td = TermOfDefence.query. \
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
join(TermOfDefence.members_of_committee, isouter=True). \
all()
return {"term_of_defences": td}
@bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
@bp.output(TemporaryAvailabilityListSchema)
def list_of_temporary_availability(examination_schedule_id: int) -> dict:
ex = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first()
if ex is None:
abort(400, "Examination Schedule didn't exist")
td = TemporaryAvailability.query. \
filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
join(TemporaryAvailability.project_supervisor). \
all()
return {"temporary_availabilities": td}

View File

@ -4,6 +4,7 @@ from apiflask import APIBlueprint
from flask import abort, Response, make_response from flask import abort, Response, make_response
from ...base.utils import paginate_models from ...base.utils import paginate_models
from ...base.mode import ModeGroups
from ...dependencies import db from ...dependencies import db
from ...examination_schedule.models import ExaminationSchedule from ...examination_schedule.models import ExaminationSchedule
from ...students.models import Group, YearGroup from ...students.models import Group, YearGroup
@ -37,7 +38,16 @@ def create_examination_schedule(year_group_id: int, data: dict) -> dict:
if data['start_date'] > data['end_date']: if data['start_date'] > data['end_date']:
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 = ExaminationSchedule(**data, year_group_id=year_group_id) duration_time = None
if yg.mode == ModeGroups.NON_STATIONARY.value:
duration_time = 20
elif yg.mode in [ModeGroups.STATIONARY.value, ModeGroups.ENGLISH_SPEAKING_STATIONARY.value]:
duration_time = 30
if duration_time is None:
abort(400, "Invalid mode of year group!")
examination_schedule = ExaminationSchedule(**data, year_group_id=year_group_id, duration_time=duration_time)
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!"}

View File

@ -3,7 +3,7 @@ from flask import abort
from flask_sqlalchemy import get_debug_queries from flask_sqlalchemy import get_debug_queries
from ...dependencies import db from ...dependencies import db
from ...examination_schedule.models import ExaminationSchedule, Enrollment, Committee from ...examination_schedule.models import ExaminationSchedule
from ...project_supervisor.models import ProjectSupervisor from ...project_supervisor.models import ProjectSupervisor
from ..schemas import WorkloadSchema from ..schemas import WorkloadSchema

View File

@ -1,6 +1,5 @@
from flask import abort from flask import abort
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask_sqlalchemy import get_debug_queries
from ...students.models import YearGroup from ...students.models import YearGroup
from ..schemas import YearGroupSchema, MessageSchema, YearGroupPaginationSchema, YearGroupQuerySchema from ..schemas import YearGroupSchema, MessageSchema, YearGroupPaginationSchema, YearGroupQuerySchema

View File

@ -1,4 +1,4 @@
from .enrollments import EnrollmentCreateSchema from .enrollments import TermOfDefenceSchema, TermOfDefenceListSchema, TemporaryAvailabilityListSchema
from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \ from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema

View File

@ -1,8 +1,41 @@
from marshmallow import Schema, fields from marshmallow import Schema, fields, validate
from ..validators import validate_datetime_greater_than_now from ..validators import validate_datetime_greater_than_now
class EnrollmentCreateSchema(Schema): class TermOfDefenceSchema(Schema):
start_date = fields.DateTime(validate=validate_datetime_greater_than_now, 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) end_date = fields.DateTime(validate=validate_datetime_greater_than_now, required=True)
project_supervisors = fields.List(fields.Integer(required=True), validate=validate.Length(3, 3))
class ProjectSupervisorForTermOfDefenceSchema(Schema):
id = fields.Str()
first_name = fields.Str()
last_name = fields.Str()
class TermOfDefenceItemSchema(Schema):
start_date = fields.DateTime()
end_date = fields.DateTime()
members_of_committee = fields.List(fields.Nested(ProjectSupervisorForTermOfDefenceSchema))
class TermOfDefenceListSchema(Schema):
term_of_defences = fields.List(fields.Nested(TermOfDefenceItemSchema))
class ProjectSupervisorForTemporaryAvailabilitySchema(Schema):
id = fields.Str()
first_name = fields.Str()
last_name = fields.Str()
class TemporaryAvailabilityItemSchema(Schema):
start_date = fields.DateTime()
end_date = fields.DateTime()
project_supervisor = fields.Nested(ProjectSupervisorForTemporaryAvailabilitySchema)
class TemporaryAvailabilityListSchema(Schema):
temporary_availabilities = fields.List(fields.Nested(TemporaryAvailabilityItemSchema))

View File

@ -6,7 +6,7 @@ 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)
duration_time = db.Column(db.Integer) # in minutes duration_time = db.Column(db.Integer) # in minutes
start_date_for_enrollment_students = db.Column(db.DateTime) start_date_for_enrollment_students = db.Column(db.DateTime)
end_date_for_enrollment_students = db.Column(db.DateTime) end_date_for_enrollment_students = db.Column(db.DateTime)
start_date = db.Column(db.DateTime, nullable=False) start_date = db.Column(db.DateTime, nullable=False)

View File

@ -1,39 +0,0 @@
import datetime
from apiflask import APIBlueprint
from flask import abort
from ..schemas import EnrollmentPaginationSchema, EnrollmentQuerySchema, ExaminationScheduleProjectSupervisorViewSchema
from ..utils import check_examination_schedule_is_exist, get_list_of_enrollments_response
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
# list of the exam registration for students
@bp.get('/<int:examination_schedule_id>/student-view')
@bp.input(EnrollmentQuerySchema, location='query')
@bp.output(EnrollmentPaginationSchema)
def list_enrollments_for_students(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 is None or examination_schedule.end_date is None:
abort(403, "Forbidden! The examination schedule is not available yet")
if examination_schedule.start_date.timestamp() > now.timestamp():
abort(403, "Forbidden! Enrollments haven't just started!")
if examination_schedule.end_date.timestamp() < now.timestamp():
abort(400, "The exam registration has just finished!")
return get_list_of_enrollments_response(examination_schedule_id, page, per_page)
@bp.get('/<int:examination_schedule_id>/coordinator-view/')
@bp.output(ExaminationScheduleProjectSupervisorViewSchema)
def list_enrollments_for_coordinator(examination_schedule_id: int) -> dict:
return check_examination_schedule_is_exist(examination_schedule_id)

View File

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

View File

@ -1,39 +0,0 @@
from marshmallow import fields, validate, Schema
class ProjectSupervisorSchema(Schema):
first_name = fields.Str()
last_name = fields.Str()
class CommitteeSchema(Schema):
members = fields.List(fields.Nested(ProjectSupervisorSchema))
class GroupSchema(Schema):
name = fields.Str()
class EnrollmentSchema(Schema):
id = fields.Integer()
start_date = fields.DateTime()
end_date = fields.DateTime()
committee = fields.Nested(CommitteeSchema)
group = fields.Nested(GroupSchema)
class EnrollmentPaginationSchema(Schema):
enrollments = fields.List(fields.Nested(EnrollmentSchema))
max_pages = fields.Integer()
class ExaminationScheduleProjectSupervisorViewSchema(Schema):
id = fields.Integer()
start_date = fields.DateTime()
end_date = fields.DateTime()
class EnrollmentQuerySchema(Schema):
page = fields.Integer()
per_page = fields.Integer()

View File

@ -1,27 +0,0 @@
from flask import abort
from ..dependencies import db
from .models import ExaminationSchedule
from ..students.models import Group
from ..base.utils import paginate_models
def check_examination_schedule_is_exist(examination_schedule_id: int) -> ExaminationSchedule:
examination_schedule = db.session.query(ExaminationSchedule).filter(
ExaminationSchedule.id == examination_schedule_id).first()
if examination_schedule is None:
abort(404, "Examination Schedule doesn't exist!")
return examination_schedule
def get_list_of_enrollments_response(examination_schedule_id: int, page: int = None, per_page: int = None) -> dict:
enrollments_query = db.session.query(Enrollment). \
join(Group, isouter=True).join(Committee, isouter=True). \
join(ExaminationSchedule, isouter=True). \
filter(ExaminationSchedule.id == examination_schedule_id)
data = paginate_models(page, enrollments_query, per_page)
return {"enrollments": data["items"], "max_pages": data["max_pages"]}

View File

@ -1,27 +0,0 @@
import datetime
from flask import abort
from ..dependencies import db
from ..examination_schedule.models import ExaminationSchedule
def get_enrollment_by_enrollment_and_examination_schedule_ids(examination_schedule_id: int,
enrollment_id: int) -> None:
enrollment = db.session.query(Enrollment). \
join(ExaminationSchedule, isouter=True).join(Committee, isouter=True). \
filter(ExaminationSchedule.id == examination_schedule_id). \
filter(Enrollment.id == enrollment_id). \
first()
if enrollment is None:
abort(404, "Examination schedule doesn't exist!")
return enrollment
def check_the_enrollments_has_just_started(start_date: datetime.datetime, action: str) -> None:
now = datetime.datetime.utcnow()
if start_date is not None and start_date.timestamp() < now.timestamp():
abort(403, f"Forbidden! Enrollment has just started! You cannot {action} from the exam committees!")

View File

@ -4,7 +4,7 @@ from apiflask import APIBlueprint
from flask import abort from flask import abort
from ..schemas import MessageSchema, TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \ from ..schemas import MessageSchema, TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
ListOfFreeTimesSchema ListOfFreeTimesSchema, ListOfTermOfDefenceSchema
from ...dependencies import db from ...dependencies import db
from ..models import ProjectSupervisor from ..models import ProjectSupervisor
from ...examination_schedule.models import ExaminationSchedule, TemporaryAvailability, TermOfDefence from ...examination_schedule.models import ExaminationSchedule, TemporaryAvailability, TermOfDefence
@ -32,7 +32,9 @@ def set_your_free_time_to_examination_schedule(examination_schedule_id: int, dat
if sd > ed: if sd > ed:
abort(400, "Invalid data! End date must be greater than start date!") abort(400, "Invalid data! End date must be greater than start date!")
if not (es.start_date >= sd and es.end_date <= ed): print(es.start_date.timestamp() >= sd.timestamp())
print(es.end_date.timestamp() <= ed.timestamp())
if not (es.start_date.timestamp() <= sd.timestamp() and es.end_date.timestamp() >= ed.timestamp()):
abort(400, "Invalid date ranges!") abort(400, "Invalid date ranges!")
now = datetime.utcnow() now = datetime.utcnow()
@ -47,18 +49,18 @@ def set_your_free_time_to_examination_schedule(examination_schedule_id: int, dat
# implement logic # implement logic
pass pass
ta = TemporaryAvailability(**data, examination_schedule_id=examination_schedule_id, ta = TemporaryAvailability(**data, examination_schedule_id=examination_schedule_id)
project_supervisor_id=project_supervisor.id)
db.session.add(ta) db.session.add(ta)
db.session.commit() db.session.commit()
return {"message": "You have just assigned your free time!"} return {"message": "You have just assigned your free time!"}
@bp.delete('/<int:examination_schedule_id>/enrollments/<int:id>/') @bp.delete('/<int:examination_schedule_id>/enrollments/<int:temporary_availability_id>/')
@bp.input(TemporaryProjectSupervisorSchema) @bp.input(TemporaryProjectSupervisorSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def delete_your_free_time_from_examination_schedule(examination_schedule_id: int, id: int, data: dict) -> dict: def delete_your_free_time_from_examination_schedule(examination_schedule_id: int, temporary_availability_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:
@ -66,7 +68,7 @@ def delete_your_free_time_from_examination_schedule(examination_schedule_id: int
################ ################
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id, ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
TemporaryAvailability.project_supervisor_id == project_supervisor.id, TemporaryAvailability.project_supervisor_id == project_supervisor.id,
TemporaryAvailability.id == id).first() TemporaryAvailability.id == temporary_availability_id).first()
if ta is None: if ta is None:
abort(404, "Your free time doesn't exist!") abort(404, "Your free time doesn't exist!")
@ -76,7 +78,7 @@ def delete_your_free_time_from_examination_schedule(examination_schedule_id: int
return {"message": "You have just removed your free time!"} return {"message": "You have just removed your free time!"}
@bp.get('/<int:examination_schedule_id>/') @bp.get('/<int:examination_schedule_id>/temporary-availabilities/')
@bp.input(TemporaryProjectSupervisorSchema, location='query') @bp.input(TemporaryProjectSupervisorSchema, location='query')
@bp.output(ListOfFreeTimesSchema) @bp.output(ListOfFreeTimesSchema)
def list_enrollments_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict: def list_enrollments_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict:
@ -92,19 +94,21 @@ def list_enrollments_for_project_supervisor(examination_schedule_id: int, data:
abort(404, "Examination schedule doesn't exist!") abort(404, "Examination schedule doesn't exist!")
now = datetime.utcnow() now = datetime.utcnow()
if es.start_date_for_enrollment_students.timestamp() < now.timestamp(): start_date = es.start_date_for_enrollment_students
if start_date is not None and start_date.timestamp() < now.timestamp():
abort(403, "Forbidden! Enrollment has just started! You cannot assign to the exam committees!") abort(403, "Forbidden! Enrollment has just started! You cannot assign to the exam committees!")
# list of your term of defences first enrollment # list of your term of defences first enrollment
ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id, ta = TemporaryAvailability.query.filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id,
TemporaryAvailability.project_supervisor_id == project_supervisor.id).all() TemporaryAvailability.project_supervisor_id == project_supervisor.id).all()
return ta return {"free_times": ta}
@bp.get('/<int:examination_schedule_id>/term-of-defences/') @bp.get('/<int:examination_schedule_id>/term-of-defences/')
@bp.input(TemporaryProjectSupervisorSchema, location='query') @bp.input(TemporaryProjectSupervisorSchema, location='query')
@bp.output(ListOfFreeTimesSchema) @bp.output(ListOfTermOfDefenceSchema)
def list_created_enrollment_by_coordinator_for_project_supervisor(examination_schedule_id: int, data: dict) -> dict: def list_created_term_of_defences_by_coordinator_for_project_supervisor(examination_schedule_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:
@ -118,5 +122,5 @@ def list_created_enrollment_by_coordinator_for_project_supervisor(examination_sc
# list of your free times first enrollment # list of your free times first enrollment
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \ td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \ filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
filter_by(project_supervisor_id=project_supervisor.id).all() filter_by(id=project_supervisor.id).all()
return td return {"term_of_defences": td}

View File

@ -15,6 +15,10 @@ class ListOfFreeTimesSchema(Schema):
free_times = fields.List(fields.Nested(FreeTimeSchema)) free_times = fields.List(fields.Nested(FreeTimeSchema))
class ListOfTermOfDefenceSchema(Schema):
term_of_defences = fields.List(fields.Nested(FreeTimeSchema))
class TimeAvailabilityCreateSchema(Schema): class TimeAvailabilityCreateSchema(Schema):
start_date = fields.DateTime(required=True) start_date = fields.DateTime(required=True)
end_date = fields.DateTime(required=True) end_date = fields.DateTime(required=True)

View File

@ -1,10 +0,0 @@
import datetime
from flask import abort
from ..examination_schedule.models import ExaminationSchedule
def check_the_enrollments_has_just_started(es: ExaminationSchedule) -> None:
now = datetime.datetime.utcnow()
if es.start_date is None or es.end_date is None or not (es.start_date < now < es.end_date):
abort(403, "Forbidden! Enrollment hasn't started yet.")

View File

@ -2,8 +2,10 @@ from flask import Blueprint
from .enrollments import bp as enrollments_bp from .enrollments import bp as enrollments_bp
from .registrations import bp as registrations_bp from .registrations import bp as registrations_bp
from .year_group import bp as year_group_bp
bp = Blueprint("students", __name__, url_prefix="/students") bp = Blueprint("students", __name__, url_prefix="/students")
bp.register_blueprint(registrations_bp)
bp.register_blueprint(enrollments_bp) bp.register_blueprint(enrollments_bp)
bp.register_blueprint(registrations_bp)
bp.register_blueprint(year_group_bp)

View File

@ -3,7 +3,8 @@ import datetime
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask import abort from flask import abort
from ..schemas import MessageSchema, TemporaryStudentSchema, ExaminationScheduleListSchema from ..schemas import MessageSchema, TemporaryStudentSchema, ExaminationScheduleListSchema, \
TermOfDefenceStudentListSchema
from ...dependencies import db from ...dependencies import db
from ..models import Student, Group, TermOfDefence from ..models import Student, Group, TermOfDefence
from ...examination_schedule.models import ExaminationSchedule from ...examination_schedule.models import ExaminationSchedule
@ -12,33 +13,39 @@ from ...project_supervisor.models import ProjectSupervisor
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/<int:term_of_defence_id>/')
@bp.input(TemporaryStudentSchema) @bp.input(TemporaryStudentSchema)
@bp.output(MessageSchema) @bp.output(MessageSchema)
def assign_your_group_to_term_of_defence(examination_schedule_id: int, data: dict) -> dict: def assign_your_group_to_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!")
################ ################
term_of_defence = TermOfDefence.query.filter(TermOfDefence.id == term_of_defence_id,
TermOfDefence.examination_schedule_id == examination_schedule_id).first()
if term_of_defence is None:
abort(400, "Term of defence not found!")
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()
if st is None or st.group.project_supervisor is None: if st is None or st.groups.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!")
defence = TermOfDefence.query.filter(TermOfDefence.group_id == st.group.id, defence = TermOfDefence.query.filter(TermOfDefence.group_id == st.groups.id,
TermOfDefence.examination_schedule_id == examination_schedule_id).first() TermOfDefence.examination_schedule_id == examination_schedule_id).first()
if defence is not None: if defence is not None:
abort(400, "Your group has already assigned to any exam date!") abort(400, "Your group has already assigned to any exam date!")
g = Group.query.filter(id=st.group_id).first() g = Group.query.filter(Group.id == st.group_id).first()
td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \ td = TermOfDefence.query.join(TermOfDefence.members_of_committee). \
filter_by(project_supervisor_id=g.project_supervisor_id).first() filter_by(id=g.project_supervisor_id).first()
if td is None: if td is None:
abort(400, "Your project supervisor is not in committee!") abort(400, "Your project supervisor is not in committee!")
defence.group_id = st.group.id term_of_defence.group_id = st.groups.id
db.session.add(defence) db.session.add(term_of_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!"}
@ -59,7 +66,7 @@ def delete_your_group_from_term_of_defence(examination_schedule_id: int, term_of
if term_of_defence is None: if term_of_defence is None:
abort(404, "Term of defence doesn't exist!") abort(404, "Term of defence doesn't exist!")
if student.group.id != term_of_defence.group_id: if student.groups.id != term_of_defence.group_id:
abort(400, "You are not assigned to this group!") abort(400, "You are not assigned to this group!")
term_of_defence.group_id = None term_of_defence.group_id = None
@ -70,9 +77,9 @@ def delete_your_group_from_term_of_defence(examination_schedule_id: int, term_of
@bp.get('/examination-schedule/year-group/<int:year_group_id>/') @bp.get('/examination-schedule/year-group/<int:year_group_id>/')
@bp.input(TemporaryStudentSchema) @bp.input(TemporaryStudentSchema, location='query')
@bp.output(ExaminationScheduleListSchema) @bp.output(ExaminationScheduleListSchema)
def list_examination_schedule_for_students(year_group_id: int, data: dict) -> dict: def list_examination_schedule(year_group_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:
@ -88,10 +95,10 @@ def list_examination_schedule_for_students(year_group_id: int, data: dict) -> di
return {'examination_schedules': examination_schedules} return {'examination_schedules': examination_schedules}
@bp.get('/enrollments/') @bp.get('/examination-schedule/<int:examination_schedule_id>/enrollments/')
@bp.input(TemporaryStudentSchema) @bp.input(TemporaryStudentSchema, location='query')
@bp.output(ExaminationScheduleListSchema) @bp.output(TermOfDefenceStudentListSchema)
def list_term_of_defences_for_students(data: dict) -> dict: def list_term_of_defences(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:
@ -99,9 +106,9 @@ def list_term_of_defences_for_students(data: dict) -> 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()
term_of_defences = TermOfDefence.query.join(ExaminationSchedule, isouter=True). \ term_of_defences = TermOfDefence.query.filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
join(ExaminationSchedule, isouter=True). \
filter(ExaminationSchedule.start_date_for_enrollment_students < now). \ filter(ExaminationSchedule.start_date_for_enrollment_students < now). \
filter(ExaminationSchedule.end_date_for_enrollment_students > now). \ filter(ExaminationSchedule.end_date_for_enrollment_students > now).all()
filter(TermOfDefence.group_id == student.group_id). \
all() return {'term_of_defences': term_of_defences}
return {'examination_schedules': term_of_defences}

View File

@ -0,0 +1,32 @@
from apiflask import APIBlueprint
from flask import abort
from ...students.models import YearGroup
from ...dependencies import db
from ...base.utils import paginate_models
from ..schemas import YearGroupQueryStudentSchema, YearGroupStudentPaginationSchema
from ..models import Student
bp = APIBlueprint("year_group", __name__, url_prefix="/year-group")
@bp.get('/')
@bp.input(YearGroupQueryStudentSchema, location='query')
@bp.output(YearGroupStudentPaginationSchema)
def list_of_year_groups(query: dict) -> dict:
index = query.get('index')
st = Student.query.filter(Student.index == index).first()
if st is None:
abort(404, "Not found student!")
####################################
page = query.get('page')
per_page = query.get('per_page')
year_group_query = YearGroup.query.join(YearGroup.students). \
filter(Student.index == st.index).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']
}

View File

@ -35,3 +35,30 @@ class ExaminationScheduleSchema(Schema):
class ExaminationScheduleListSchema(Schema): class ExaminationScheduleListSchema(Schema):
examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema)) examination_schedules = fields.List(fields.Nested(ExaminationScheduleSchema))
class TermOfDefenceStudentItemSchema(Schema):
id = fields.Integer()
start_date = fields.DateTime()
end_date = fields.DateTime()
class TermOfDefenceStudentListSchema(Schema):
term_of_defences = fields.List(fields.Nested(TermOfDefenceStudentItemSchema))
class YearGroupStudentSchema(Schema):
id = fields.Integer()
name = fields.Str()
mode = fields.Str()
class YearGroupStudentPaginationSchema(Schema):
year_groups = fields.List(fields.Nested(YearGroupStudentSchema))
max_pages = fields.Integer()
class YearGroupQueryStudentSchema(Schema):
index = fields.Integer(required=True) # it will be removed
page = fields.Integer()
per_page = fields.Integer()