diff --git a/backend/app/config.py b/backend/app/config.py index 374e8d0..55363e4 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -21,6 +21,8 @@ class Config: DESCRIPTION = 'System PRI' OPENAPI_VERSION = '3.0.2' + PROJECT_PRESENTATION_TIME = 30 # in minutes + class ProductionConfig(Config): DB_SERVER = "0.0.0.0" diff --git a/backend/app/coordinator/routes/__init__.py b/backend/app/coordinator/routes/__init__.py index 1fc05b4..7372046 100644 --- a/backend/app/coordinator/routes/__init__.py +++ b/backend/app/coordinator/routes/__init__.py @@ -4,6 +4,7 @@ from .students import bp as students_bp from .project_supervisor import bp as project_supervisor_bp from .groups import bp as groups_bp from .examination_schedule import bp as examination_schedule_bp +from .enrollments import bp as enrollments_bp bp = Blueprint("coordinator", __name__, url_prefix="/coordinator") @@ -11,3 +12,4 @@ bp.register_blueprint(students_bp) bp.register_blueprint(project_supervisor_bp) bp.register_blueprint(groups_bp) bp.register_blueprint(examination_schedule_bp) +bp.register_blueprint(enrollments_bp) diff --git a/backend/app/coordinator/routes/enrollments.py b/backend/app/coordinator/routes/enrollments.py new file mode 100644 index 0000000..ee407fc --- /dev/null +++ b/backend/app/coordinator/routes/enrollments.py @@ -0,0 +1,60 @@ +import datetime + +from apiflask import APIBlueprint +from flask import abort, current_app + +from ..schemas import MessageSchema, EnrollmentCreateSchema +from ...examination_schedule.models import Enrollment, Committee, ExaminationSchedule +from ...dependencies import db + +bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") + + +@bp.post('//') +@bp.input(EnrollmentCreateSchema, location='json') +@bp.output(MessageSchema) +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() + if examination_schedule is None: + abort(404, "Examination schedule doesn't exist!") + + start_date = data['start_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!") + + delta = end_date - start_date + delta_in_minutes = delta.total_seconds() / 60 + if delta_in_minutes % prt != 0: + abort(400, "Invalid format dates!") + + amount = int(delta_in_minutes // prt) + enrollments = [] + for i in range(amount): + sd = start_date + datetime.timedelta(minutes=i * prt) + ed = start_date + datetime.timedelta(minutes=(i + 1) * prt) + enrollment = Enrollment(start_date=sd, end_date=ed) + enrollments.append(enrollment) + db.session.add_all(enrollments) + db.session.commit() + + committees = [Committee(enrollment_id=e.id) for e in enrollments] + db.session.add_all(committees) + db.session.commit() + return {"message": "Enrollments was created!"} + + +@bp.delete('//') +@bp.output(MessageSchema) +def delete_enrollment(enrollment_id: int) -> dict: + enrollment = db.session.query(Enrollment).filter(Enrollment.id == enrollment_id).first() + if enrollment is None: + abort(404, "Enrollment doesn't exist!") + db.session.delete(enrollment) + db.session.commit() + return {"message": "Enrollment was deleted!"} diff --git a/backend/app/coordinator/routes/examination_schedule.py b/backend/app/coordinator/routes/examination_schedule.py index e4899f5..7d48518 100644 --- a/backend/app/coordinator/routes/examination_schedule.py +++ b/backend/app/coordinator/routes/examination_schedule.py @@ -27,7 +27,6 @@ def create_examination_schedule(data: dict) -> dict: examination_schedule = ExaminationSchedule(**data) db.session.add(examination_schedule) db.session.commit() - return {"message": "Examination schedule was created!"} @@ -45,6 +44,17 @@ def update_title_examination_schedule(id: int, data: dict) -> dict: return {"message": "Examination schedule was updated!"} +@bp.delete('//') +@bp.output(MessageSchema) +def delete_examination_schedule(id: int) -> dict: + examination_schedule = db.session.query(ExaminationSchedule).filter(ExaminationSchedule.id == id).first() + if examination_schedule is None: + abort(404, "Examination schedule doesn't exist!") + db.session.delete(examination_schedule) + db.session.commit() + return {"message": "Examination schedule was deleted!"} + + @bp.put('//date') @bp.input(ExaminationScheduleUpdateSchema) @bp.output(MessageSchema) diff --git a/backend/app/coordinator/schemas/__init__.py b/backend/app/coordinator/schemas/__init__.py index ca8aeb3..3ff75e7 100644 --- a/backend/app/coordinator/schemas/__init__.py +++ b/backend/app/coordinator/schemas/__init__.py @@ -1,8 +1,9 @@ +from .enrollments import EnrollmentCreateSchema +from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \ + ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \ ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \ StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \ StudentQuerySchema -from .examination_schedule import ExaminationScheduleSchema, ExaminationScheduleUpdateSchema, \ - ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema diff --git a/backend/app/coordinator/schemas/enrollments.py b/backend/app/coordinator/schemas/enrollments.py new file mode 100644 index 0000000..713cc38 --- /dev/null +++ b/backend/app/coordinator/schemas/enrollments.py @@ -0,0 +1,11 @@ +from marshmallow import Schema, fields + +from ..validators import validate_datetime_greater_than_now + + +class EnrollmentCreateSchema(Schema): + 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 Meta: + datetimeformat = '%Y-%m-%d %H:%M:%S' diff --git a/backend/app/examination_schedule/models.py b/backend/app/examination_schedule/models.py index 96df07a..f1692c1 100644 --- a/backend/app/examination_schedule/models.py +++ b/backend/app/examination_schedule/models.py @@ -17,14 +17,14 @@ class Enrollment(Base): end_date = db.Column(db.DateTime, nullable=False) examination_schedule_id = db.Column(db.Integer, db.ForeignKey('examination_schedules.id')) examination_schedule = db.relationship('ExaminationSchedule', backref='enrollments') - committee = db.relationship("Committee", uselist=False, backref='enrollment') + committee = db.relationship("Committee", uselist=False, backref=db.backref('enrollment', passive_deletes=True)) group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) class Committee(Base): __tablename__ = 'committees' - enrollment_id = db.Column(db.Integer, db.ForeignKey('enrollments.id')) + enrollment_id = db.Column(db.Integer, db.ForeignKey('enrollments.id', ondelete='CASCADE')) members = db.relationship('ProjectSupervisor', secondary='committees_projects_supervisors', backref='committees') diff --git a/backend/app/examination_schedule/routes/__init__.py b/backend/app/examination_schedule/routes/__init__.py index 738fb6f..30893a6 100644 --- a/backend/app/examination_schedule/routes/__init__.py +++ b/backend/app/examination_schedule/routes/__init__.py @@ -1,3 +1,7 @@ from flask import Blueprint +from .enrollments import bp as enrollments_bp + bp = Blueprint("examination_schedule", __name__, url_prefix="/examination_schedule") + +bp.register_blueprint(enrollments_bp) diff --git a/backend/app/examination_schedule/routes/enrollments.py b/backend/app/examination_schedule/routes/enrollments.py new file mode 100644 index 0000000..dd34cd2 --- /dev/null +++ b/backend/app/examination_schedule/routes/enrollments.py @@ -0,0 +1,9 @@ +from apiflask import APIBlueprint + +bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") + + +# list enrollments in examination schedule module for students, coordinator and project_supervisor +@bp.get('/') +def list_enrollments() -> dict: + pass diff --git a/backend/migrations/versions/9874e26f2b87_.py b/backend/migrations/versions/97c55960cd98_.py similarity index 95% rename from backend/migrations/versions/9874e26f2b87_.py rename to backend/migrations/versions/97c55960cd98_.py index 83bb654..df2a874 100644 --- a/backend/migrations/versions/9874e26f2b87_.py +++ b/backend/migrations/versions/97c55960cd98_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: 9874e26f2b87 +Revision ID: 97c55960cd98 Revises: ceaefb33117e -Create Date: 2022-10-26 09:46:09.397814 +Create Date: 2022-10-26 13:00:18.439990 """ from alembic import op @@ -10,7 +10,7 @@ import sqlalchemy as sa # revision identifiers, used by Alembic. -revision = '9874e26f2b87' +revision = '97c55960cd98' down_revision = 'ceaefb33117e' branch_labels = None depends_on = None @@ -39,7 +39,7 @@ def upgrade(): op.create_table('committees', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), sa.Column('enrollment_id', sa.Integer(), nullable=True), - sa.ForeignKeyConstraint(['enrollment_id'], ['enrollments.id'], ), + sa.ForeignKeyConstraint(['enrollment_id'], ['enrollments.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('committees_projects_supervisors',