diff --git a/backend/app/config.py b/backend/app/config.py index 01c1d8f..04e893f 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -18,7 +18,7 @@ class Config: SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_DATABASE_URI = f'sqlite:///{BASE_DIR / "db.sqlite"}' LIMIT_STUDENTS_PER_GROUP = 5 - LIMIT_PERSONS_PER_COMMITTEE = 4 + LIMIT_MEMBERS_PER_COMMITTEE = 3 DESCRIPTION = 'System PRI' OPENAPI_VERSION = '3.0.2' diff --git a/backend/app/coordinator/routes/enrollments.py b/backend/app/coordinator/routes/enrollments.py index f60c1cf..e32a9ff 100644 --- a/backend/app/coordinator/routes/enrollments.py +++ b/backend/app/coordinator/routes/enrollments.py @@ -1,7 +1,8 @@ import datetime +from itertools import islice from apiflask import APIBlueprint -from flask import abort +from flask import abort, current_app from sqlalchemy import or_, and_ from ..schemas import MessageSchema, TermOfDefenceSchema, TermOfDefenceListSchema, \ @@ -10,13 +11,64 @@ from ...examination_schedule.models import ExaminationSchedule, TermOfDefence, T from ...students.models import YearGroup from ...project_supervisor.models import ProjectSupervisor from ...dependencies import db +from ..utils import generate_range_dates bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments") @bp.post('//generate') +@bp.output(MessageSchema) def generate_term_of_defence_for_this_examination_schedule(examination_schedule_id: int) -> dict: - pass + ex = ExaminationSchedule.query.filter(ExaminationSchedule.id == examination_schedule_id).first() + if ex is None: + abort(404, "Not found examination schedule!") + + # print(ex.start_date.date()) + # print(ex.end_date.date()) + dates = generate_range_dates(ex.start_date, ex.end_date, ex.duration_time) + # print(dates) + limit = current_app.config.get('LIMIT_MEMBERS_PER_COMMITTEE', 3) + + # in future optimize sql query + # project_supervisor cache in memory (flyweight) + # while True: + # sliced_dates = islice(dates, 1) + # list_of_dates = list(sliced_dates) + # + # if len(list_of_dates) == 0: + # break + for d in dates: + e = d + datetime.timedelta(minutes=ex.duration_time) + # print(f"{d} - {e}") + temporary_availabilities = TemporaryAvailability.query.filter( + TemporaryAvailability.examination_schedule_id == examination_schedule_id). \ + filter(TemporaryAvailability.start_date <= d, + TemporaryAvailability.end_date >= e).all() + if len(temporary_availabilities) >= limit: + # create term of defence + # check term of defence exist in this date range + td = TermOfDefence.query.filter(or_(and_(TermOfDefence.start_date <= d, TermOfDefence.end_date >= e), + and_(TermOfDefence.start_date > d, TermOfDefence.end_date >= e, + TermOfDefence.start_date < e), + and_(TermOfDefence.start_date <= d, TermOfDefence.end_date > d, + TermOfDefence.end_date < e) + )).first() + if td is None: + term_of_defence = TermOfDefence(start_date=d, end_date=e, examination_schedule_id=examination_schedule_id) + db.session.add(term_of_defence) + db.session.commit() + project_supervisors_ids = [] + for i in range(limit): + ta = temporary_availabilities[i] + project_supervisors_ids.append(ta.project_supervisor_id) + project_supervisors = ProjectSupervisor.query.filter( + or_(*[ProjectSupervisor.id == idx for idx in project_supervisors_ids])).all() + for p in project_supervisors: + term_of_defence.members_of_committee.append(p) + db.session.commit() + + # print(temporary_availabilities) + return {"message": "Term of defences was generated!"} @bp.post('//add') diff --git a/backend/app/coordinator/utils.py b/backend/app/coordinator/utils.py index a337871..2dde9ec 100644 --- a/backend/app/coordinator/utils.py +++ b/backend/app/coordinator/utils.py @@ -1,8 +1,9 @@ -import datetime +import copy +from datetime import datetime, timedelta from collections import defaultdict from io import BytesIO from itertools import chain -from typing import Generator, Any, List, Tuple +from typing import Generator, Union, Any, List, Tuple import pandas as pd from reportlab.lib import colors @@ -65,6 +66,18 @@ def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str: return df.to_csv(index=False) +def generate_range_dates(start_date: datetime, end_date: datetime, step_in_minutes: int) -> \ + Generator[Union[datetime, timedelta], Any, None]: + current_date = copy.copy(start_date) + while True: + next_date = current_date + timedelta(minutes=step_in_minutes) + + if next_date > end_date: + break + yield current_date + current_date = copy.copy(next_date) + + def generate_examination_schedule_pdf_file(title: str, nested_enrollments: List[List[object]]) -> bytes: pagesize = (297 * mm, 210 * mm) headers = ["lp.", "Godzina", "Nazwa projektu", "Opiekun", "Zespol", "Komisja"]