fix group, students, project_supervisor endpoints for coordinator, fix importing csv students endpoint and add copy project supervisors from last year group, refactor code
This commit is contained in:
parent
48be4c6345
commit
038f9da93d
@ -7,11 +7,10 @@ from flask_cors import CORS
|
|||||||
from .config import config
|
from .config import config
|
||||||
from .dependencies import db, ma
|
from .dependencies import db, ma
|
||||||
from .commands.startapp import startapp
|
from .commands.startapp import startapp
|
||||||
from .commands.init_db import init_db
|
|
||||||
from .commands.clear_db import clear_db
|
from .commands.clear_db import clear_db
|
||||||
from .utils import import_models
|
from .utils import import_models
|
||||||
from .api import api_bp
|
from .api import api_bp
|
||||||
from .errors import request_entity_too_large, register_error_handlers
|
from .errors import register_error_handlers
|
||||||
|
|
||||||
|
|
||||||
def create_app(config_name: str = '') -> APIFlask:
|
def create_app(config_name: str = '') -> APIFlask:
|
||||||
@ -37,11 +36,9 @@ def create_app(config_name: str = '') -> APIFlask:
|
|||||||
|
|
||||||
# register commands
|
# register commands
|
||||||
app.cli.add_command(startapp)
|
app.cli.add_command(startapp)
|
||||||
app.cli.add_command(init_db)
|
|
||||||
app.cli.add_command(clear_db)
|
app.cli.add_command(clear_db)
|
||||||
|
|
||||||
# register errors
|
# register errors
|
||||||
register_error_handlers(app)
|
register_error_handlers(app)
|
||||||
# app.register_error_handler(413, request_entity_too_large)
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
@ -12,4 +12,4 @@ class Person(db.Model):
|
|||||||
|
|
||||||
first_name = db.Column(db.String(255), index=True, nullable=False)
|
first_name = db.Column(db.String(255), index=True, nullable=False)
|
||||||
last_name = db.Column(db.String(255), index=True, nullable=False)
|
last_name = db.Column(db.String(255), index=True, nullable=False)
|
||||||
email = db.Column(db.String(120), unique=True)
|
email = db.Column(db.String(120), index=True, nullable=False)
|
||||||
|
5
backend/app/base/schemas.py
Normal file
5
backend/app/base/schemas.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from marshmallow import fields, Schema
|
||||||
|
|
||||||
|
|
||||||
|
class MessageSchema(Schema):
|
||||||
|
message = fields.Str()
|
@ -1,37 +0,0 @@
|
|||||||
from flask.cli import with_appcontext
|
|
||||||
from click import command
|
|
||||||
|
|
||||||
from ..dependencies import db
|
|
||||||
# from ..factory import ProjectSupervisorFactory, GroupFactory, StudentFactory
|
|
||||||
|
|
||||||
|
|
||||||
@command('init_db')
|
|
||||||
@with_appcontext
|
|
||||||
def init_db() -> None:
|
|
||||||
"""Fill database with some data"""
|
|
||||||
db.drop_all()
|
|
||||||
db.create_all()
|
|
||||||
#
|
|
||||||
# num_of_supervisors = 5
|
|
||||||
#
|
|
||||||
# projects_supervisors = [ProjectSupervisorFactory() for _ in range(num_of_supervisors)]
|
|
||||||
# db.session.add_all(projects_supervisors)
|
|
||||||
# db.session.commit()
|
|
||||||
#
|
|
||||||
# groups = [GroupFactory(project_supervisor=projects_supervisors[i]) for i in range(num_of_supervisors)]
|
|
||||||
# db.session.add_all(groups)
|
|
||||||
# db.session.commit()
|
|
||||||
#
|
|
||||||
# num_of_students = num_of_supervisors * 3
|
|
||||||
# students = [StudentFactory(group=groups[i % num_of_supervisors]) for i in range(num_of_students)]
|
|
||||||
#
|
|
||||||
# max_count = 10
|
|
||||||
# max_length = len(students)
|
|
||||||
# start_count = 0
|
|
||||||
#
|
|
||||||
# while True:
|
|
||||||
# if start_count > max_length:
|
|
||||||
# break
|
|
||||||
# db.session.add_all(students[start_count:max_count])
|
|
||||||
# db.session.commit()
|
|
||||||
# start_count += max_count
|
|
@ -1,5 +0,0 @@
|
|||||||
# from ..base.models import Base
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Coordinator(Base):
|
|
||||||
# __tablename__ = 'coordinators'
|
|
@ -5,12 +5,13 @@ from flask import abort, current_app
|
|||||||
from sqlalchemy import or_, and_
|
from sqlalchemy import or_, and_
|
||||||
from flask_sqlalchemy import get_debug_queries
|
from flask_sqlalchemy import get_debug_queries
|
||||||
|
|
||||||
from ..schemas import MessageSchema, TermOfDefenceSchema, TermOfDefenceListSchema, \
|
from ..schemas import TermOfDefenceSchema, TemporaryAvailabilityListSchema, AssignedGroupToTermOfDefenceListSchema, \
|
||||||
TemporaryAvailabilityListSchema, AssignedGroupToTermOfDefenceListSchema, GroupIdSchema
|
GroupIdSchema
|
||||||
from ...examination_schedule.models import TermOfDefence, TemporaryAvailability, committee
|
from ...examination_schedule.models import TermOfDefence, TemporaryAvailability
|
||||||
from ...students.models import YearGroup
|
from ...students.models import YearGroup
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
from ..utils import generate_range_dates
|
from ..utils import generate_range_dates
|
||||||
from ..query.enrollments import get_term_of_defence_by_id_and_examination_schedule_id, set_new_group_to_term_of_defence, \
|
from ..query.enrollments import get_term_of_defence_by_id_and_examination_schedule_id, set_new_group_to_term_of_defence, \
|
||||||
get_examination_schedule_by_id
|
get_examination_schedule_by_id
|
||||||
@ -18,68 +19,6 @@ from ..query.enrollments import get_term_of_defence_by_id_and_examination_schedu
|
|||||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
|
bp = APIBlueprint("enrollments", __name__, url_prefix="/enrollments")
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/<int:examination_schedule_id>/generate')
|
|
||||||
@bp.output(MessageSchema)
|
|
||||||
def generate_term_of_defence_for_this_examination_schedule(examination_schedule_id: int) -> dict:
|
|
||||||
ex = get_examination_schedule_by_id(examination_schedule_id)
|
|
||||||
limit = current_app.config.get('LIMIT_MEMBERS_PER_COMMITTEE', 3)
|
|
||||||
|
|
||||||
term_of_defences = TermOfDefence.query. \
|
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id).first()
|
|
||||||
if term_of_defences is not None:
|
|
||||||
abort(400,
|
|
||||||
"First you have to delete all term of defences for this examination schedule to generate them again!")
|
|
||||||
|
|
||||||
temporary_availabilities = TemporaryAvailability.query. \
|
|
||||||
filter(TemporaryAvailability.examination_schedule_id == examination_schedule_id). \
|
|
||||||
join(TemporaryAvailability.project_supervisor). \
|
|
||||||
all()
|
|
||||||
if len(temporary_availabilities) == 0:
|
|
||||||
abort(404, "Not found temporary availabilities for project supervisors")
|
|
||||||
|
|
||||||
dates = generate_range_dates(ex.start_date, ex.end_date, ex.duration_time)
|
|
||||||
|
|
||||||
term_of_defences = []
|
|
||||||
for d in dates:
|
|
||||||
e = d + datetime.timedelta(minutes=ex.duration_time)
|
|
||||||
t = list(filter(lambda ta: ta.start_date <= d and ta.end_date >= e, temporary_availabilities))
|
|
||||||
if len(t) >= limit:
|
|
||||||
projects_supervisors = [t[i].project_supervisor for i in range(limit)]
|
|
||||||
term_of_defence = TermOfDefence(start_date=d, end_date=e, examination_schedule_id=examination_schedule_id)
|
|
||||||
term_of_defence.members_of_committee = projects_supervisors
|
|
||||||
term_of_defences.append(term_of_defence)
|
|
||||||
db.session.add_all(term_of_defences)
|
|
||||||
db.session.commit()
|
|
||||||
return {"message": "Term of defences was generated!"}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/<int:examination_schedule_id>/clear-term-of-defences/')
|
|
||||||
@bp.output(MessageSchema)
|
|
||||||
def clear_generated_term_of_defences(examination_schedule_id: int) -> dict:
|
|
||||||
get_examination_schedule_by_id(examination_schedule_id)
|
|
||||||
|
|
||||||
# count_defences = db.func.count(ProjectSupervisor.id)
|
|
||||||
# td = db.session.query(TermOfDefence, count_defences). \
|
|
||||||
# join(ProjectSupervisor, isouter=True). \
|
|
||||||
# filter(TermOfDefence.examination_schedule_id == examination_schedule_id). \
|
|
||||||
# group_by(TermOfDefence.id).having(count_defences > 0).first()
|
|
||||||
# print(td)
|
|
||||||
# if td is not None:
|
|
||||||
# abort(400, "First you remove group assigned to term of defence to clear term of defences!")
|
|
||||||
|
|
||||||
td = TermOfDefence.query. \
|
|
||||||
filter(TermOfDefence.examination_schedule_id == examination_schedule_id).all()
|
|
||||||
while True:
|
|
||||||
for t in td[0:10]:
|
|
||||||
db.session.delete(t)
|
|
||||||
db.session.commit()
|
|
||||||
if len(td) == 0:
|
|
||||||
break
|
|
||||||
td[0:10] = []
|
|
||||||
# print(len(get_debug_queries()))
|
|
||||||
return {"message": "Term of defences was deleted!"}
|
|
||||||
|
|
||||||
|
|
||||||
@bp.post('/<int:examination_schedule_id>/add')
|
@bp.post('/<int:examination_schedule_id>/add')
|
||||||
@bp.input(TermOfDefenceSchema)
|
@bp.input(TermOfDefenceSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
|
@ -9,9 +9,10 @@ from ...dependencies import db
|
|||||||
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
from ...examination_schedule.models import ExaminationSchedule, TermOfDefence
|
||||||
from ...students.models import Group, YearGroup
|
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, \
|
||||||
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
ExaminationSchedulesQuerySchema, ExaminationSchedulesPaginationSchema
|
||||||
from ..utils import generate_examination_schedule_pdf_file
|
from ..utils import generate_examination_schedule_pdf_file
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
bp = APIBlueprint("examination_schedule", __name__, url_prefix="/examination_schedule")
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
from flask import abort, current_app
|
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 ...students.models import Group, Student, YearGroup, ProjectGradeSheet
|
from ...students.models import Group, Student, YearGroup, ProjectGradeSheet
|
||||||
from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ..schemas import GroupEditSchema, GroupsPaginationSchema, GroupCreateSchema, MessageSchema, GroupQuerySchema, \
|
from ..schemas import GroupEditSchema, GroupsPaginationSchema, GroupCreateSchema, GroupQuerySchema, DetailGroupSchema
|
||||||
DetailGroupSchema
|
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ...base.utils import paginate_models
|
from ...base.utils import paginate_models
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
from ..utils import attach_points_for_first_and_second_term_to_group_models
|
from ..utils import attach_points_for_first_and_second_term_to_group_models
|
||||||
|
|
||||||
bp = APIBlueprint("groups", __name__, url_prefix="/groups")
|
bp = APIBlueprint("groups", __name__, url_prefix="/groups")
|
||||||
@ -38,7 +38,7 @@ def list_groups(year_group_id: int, query: dict) -> dict:
|
|||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageSchema, status_code=201)
|
||||||
def create_group(year_group_id: int, data: dict) -> dict:
|
def create_group(year_group_id: int, data: dict) -> dict:
|
||||||
name = data['name']
|
name = data['name']
|
||||||
students_indexes = data['students']
|
students_ids = 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()
|
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
@ -47,33 +47,21 @@ def create_group(year_group_id: int, data: dict) -> dict:
|
|||||||
|
|
||||||
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')
|
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
abort(404, f"Not found project supervisor!")
|
abort(404, f"Not found project supervisor!")
|
||||||
elif limit_student_per_group is not None and limit_student_per_group < len(students_indexes):
|
|
||||||
abort(400, f"Too much students you want add to group, "
|
|
||||||
f"The group can have only {limit_student_per_group} students")
|
|
||||||
|
|
||||||
limit = db.session.query(db.func.count(ProjectSupervisor.id)). \
|
|
||||||
join(Group).filter(ProjectSupervisor.id == project_supervisor_id).group_by(ProjectSupervisor.id).scalar()
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
group = Group(name=name, project_supervisor_id=project_supervisor_id, year_group_id=year_group_id)
|
group = Group(name=name, project_supervisor_id=project_supervisor_id, year_group_id=year_group_id)
|
||||||
|
|
||||||
students_without_groups = db.session.query(Student, Group). \
|
students_without_groups = db.session.query(Student, Group). \
|
||||||
join(Group, Student.groups). \
|
join(Group, Student.groups). \
|
||||||
filter(Group.year_group_id == year_group_id). \
|
filter(Group.year_group_id == year_group_id). \
|
||||||
filter(db.or_(*[Student.index == idx for idx in students_indexes])).all()
|
filter(db.or_(*[Student.id == st_id for st_id in students_ids])).all()
|
||||||
|
|
||||||
if len(students_without_groups) > 0:
|
if len(students_without_groups) > 0:
|
||||||
abort(400, "One or more students have already belonged to group!")
|
abort(400, "One or more students have already belonged to group!")
|
||||||
|
|
||||||
students = db.session.query(Student).filter(Student.index.in_(students_indexes)).all()
|
students = db.session.query(Student).filter(Student.id.in_(students_ids)).all()
|
||||||
if len(students) != len(students_indexes):
|
if len(students) != len(students_ids):
|
||||||
abort(404, "Not found students!")
|
abort(404, "Not found students!")
|
||||||
|
|
||||||
db.session.add(group)
|
db.session.add(group)
|
||||||
@ -81,9 +69,6 @@ def create_group(year_group_id: int, data: dict) -> dict:
|
|||||||
|
|
||||||
for student in students:
|
for student in students:
|
||||||
group.students.append(student)
|
group.students.append(student)
|
||||||
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
pgs = ProjectGradeSheet(group_id=group.id)
|
pgs = ProjectGradeSheet(group_id=group.id)
|
||||||
db.session.add(pgs)
|
db.session.add(pgs)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -91,19 +76,19 @@ def create_group(year_group_id: int, data: dict) -> dict:
|
|||||||
return {"message": "Group was created!"}
|
return {"message": "Group was created!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:id>/detail/")
|
@bp.get("/<int:group_id>/detail/")
|
||||||
@bp.output(DetailGroupSchema)
|
@bp.output(DetailGroupSchema)
|
||||||
def detail_group(id: int) -> Group:
|
def detail_group(group_id: int) -> Group:
|
||||||
group = Group.query.filter_by(id=id).first()
|
group = Group.query.filter_by(id=group_id).first()
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, f"Not found group!")
|
||||||
return group
|
return group
|
||||||
|
|
||||||
|
|
||||||
@bp.delete("/<int:id>/")
|
@bp.delete("/<int:group_id>/")
|
||||||
@bp.output(MessageSchema, status_code=202)
|
@bp.output(MessageSchema, status_code=202)
|
||||||
def delete_group(id: int) -> dict:
|
def delete_group(group_id: int) -> dict:
|
||||||
group = Group.query.filter_by(id=id).first()
|
group = Group.query.filter_by(id=group_id).first()
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, f"Not found group!")
|
||||||
|
|
||||||
@ -113,26 +98,26 @@ def delete_group(id: int) -> dict:
|
|||||||
return {"message": "Group was deleted!"}
|
return {"message": "Group was deleted!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.put("/<int:id>/")
|
@bp.put("/<int:group_id>/")
|
||||||
@bp.input(GroupEditSchema)
|
@bp.input(GroupEditSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def edit_group(id: int, data: dict) -> dict:
|
def edit_group(group_id: int, data: dict) -> dict:
|
||||||
if not data:
|
if not data:
|
||||||
abort(400, 'You have passed empty data!')
|
abort(400, 'You have passed empty data!')
|
||||||
|
|
||||||
group_query = Group.query.filter_by(id=id)
|
group_query = Group.query.filter_by(id=group_id)
|
||||||
group = group_query.first()
|
group = group_query.first()
|
||||||
|
|
||||||
if group is None:
|
if group is None:
|
||||||
abort(404, f"Not found group!")
|
abort(404, f"Not found group!")
|
||||||
|
|
||||||
students_indexes = data.get('students')
|
students_ids = data.get('students')
|
||||||
name = data.get('name')
|
name = data.get('name')
|
||||||
project_supervisor_id = data.get('project_supervisor_id')
|
project_supervisor_id = data.get('project_supervisor_id')
|
||||||
|
|
||||||
if students_indexes is not None:
|
if students_ids is not None:
|
||||||
students = db.session.query(Student).filter(Student.index.in_(students_indexes)).all()
|
students = db.session.query(Student).filter(Student.id.in_(students_ids)).all()
|
||||||
if len(students_indexes) != len(students):
|
if len(students_ids) != len(students):
|
||||||
abort(404, 'Not found students!')
|
abort(404, 'Not found students!')
|
||||||
group.students = students
|
group.students = students
|
||||||
|
|
||||||
|
@ -2,41 +2,21 @@ 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, YearGroupProjectSupervisors
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ...students.models import Group, YearGroup
|
from ...students.models import Group, YearGroup
|
||||||
from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \
|
from ..schemas import ProjectSupervisorSchema, ProjectSupervisorEditSchema, ProjectSupervisorsPaginationSchema, \
|
||||||
ProjectSupervisorCreateSchema, MessageSchema, ProjectSupervisorQuerySchema, ProjectSupervisorYearGroupSchema
|
ProjectSupervisorCreateSchema, MessageWithIdSchema, ProjectSupervisorQuerySchema
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
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.get("/")
|
|
||||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
|
||||||
@bp.output(ProjectSupervisorsPaginationSchema)
|
|
||||||
def list_project_supervisors(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(
|
|
||||||
None, 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.get("/<int:year_group_id>/")
|
@bp.get("/<int:year_group_id>/")
|
||||||
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
@bp.input(ProjectSupervisorQuerySchema, location='query')
|
||||||
@bp.output(ProjectSupervisorsPaginationSchema)
|
@bp.output(ProjectSupervisorsPaginationSchema)
|
||||||
def list_project_supervisors_by_year_group(year_group_id: int, query: dict) -> dict:
|
def list_project_supervisors(year_group_id: int, 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')
|
||||||
@ -54,44 +34,44 @@ def list_project_supervisors_by_year_group(year_group_id: int, query: dict) -> d
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@bp.post("/")
|
@bp.post("/<int:year_group_id>/")
|
||||||
@bp.input(ProjectSupervisorCreateSchema)
|
@bp.input(ProjectSupervisorCreateSchema)
|
||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageWithIdSchema, status_code=201)
|
||||||
def create_project_supervisor(data: dict) -> dict:
|
def create_project_supervisor(year_group_id: int, data: dict) -> dict:
|
||||||
first_name = data['first_name']
|
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
last_name = data['last_name']
|
if year_group is None:
|
||||||
project_supervisor = ProjectSupervisor.query.filter_by(first_name=first_name).filter_by(last_name=last_name).first()
|
abort(404, "Not found year group!")
|
||||||
|
|
||||||
|
email = data['email']
|
||||||
|
project_supervisor = ProjectSupervisor.query.filter(ProjectSupervisor.email == email).first()
|
||||||
if project_supervisor is not None:
|
if project_supervisor is not None:
|
||||||
abort(400, "Project Supervisor has already exists!")
|
abort(400, "Project Supervisor has already exists!")
|
||||||
|
|
||||||
project_supervisor = ProjectSupervisor(**data)
|
project_supervisor = ProjectSupervisor(**data, year_group_id=year_group_id)
|
||||||
|
|
||||||
db.session.add(project_supervisor)
|
db.session.add(project_supervisor)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return {"message": "Project Supervisor was created!", "id": project_supervisor.id}
|
return {"message": "Project Supervisor was created!", "id": project_supervisor.id}
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:id>/detail/")
|
@bp.get("/<int:project_supervisor_id>/detail/")
|
||||||
@bp.output(ProjectSupervisorSchema)
|
@bp.output(ProjectSupervisorSchema)
|
||||||
def detail_project_supervisor(id: int) -> ProjectSupervisor:
|
def detail_project_supervisor(project_supervisor_id: int) -> ProjectSupervisor:
|
||||||
project_supervisor = ProjectSupervisor.query.filter_by(id=id).first()
|
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
abort(404, 'Not found project supervisor!')
|
abort(404, 'Not found project supervisor!')
|
||||||
return project_supervisor
|
return project_supervisor
|
||||||
|
|
||||||
|
|
||||||
@bp.delete("/<int:id>/")
|
@bp.delete("/<int:project_supervisor_id>/")
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def delete_project_supervisor(id: int) -> dict:
|
def delete_project_supervisor(project_supervisor_id: int) -> dict:
|
||||||
project_supervisor = ProjectSupervisor.query.filter_by(id=id).first()
|
project_supervisor = ProjectSupervisor.query.filter_by(id=project_supervisor_id).first()
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
abort(404, "Not found project supervisor!")
|
abort(404, "Not found project supervisor!")
|
||||||
|
|
||||||
count_groups = db.session.query(db.func.count(ProjectSupervisor.id)).join(Group). \
|
count_groups = len(Group.query.filter(Group.project_supervisor_id == project_supervisor.id).all())
|
||||||
filter(ProjectSupervisor.id == id).group_by(ProjectSupervisor.id).scalar()
|
if count_groups > 0:
|
||||||
|
|
||||||
if count_groups is not None and count_groups > 0:
|
|
||||||
abort(400, "Project Supervisor has at least one group!")
|
abort(400, "Project Supervisor has at least one group!")
|
||||||
|
|
||||||
db.session.delete(project_supervisor)
|
db.session.delete(project_supervisor)
|
||||||
@ -99,14 +79,14 @@ def delete_project_supervisor(id: int) -> dict:
|
|||||||
return {"message": "Project Supervisor was deleted!"}
|
return {"message": "Project Supervisor was deleted!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.put("/<int:id>/")
|
@bp.put("/<int:project_supervisor_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(project_supervisor_id: int, data: dict) -> dict:
|
||||||
if not data:
|
if not data:
|
||||||
abort(400, 'You have passed empty data!')
|
abort(400, 'You have passed empty data!')
|
||||||
|
|
||||||
project_supervisor_query = ProjectSupervisor.query.filter_by(id=id)
|
project_supervisor_query = ProjectSupervisor.query.filter_by(id=project_supervisor_id)
|
||||||
project_supervisor = project_supervisor_query.first()
|
project_supervisor = project_supervisor_query.first()
|
||||||
|
|
||||||
if project_supervisor is None:
|
if project_supervisor is None:
|
||||||
@ -117,65 +97,27 @@ def edit_project_supervisor(id: int, data: dict) -> dict:
|
|||||||
return {"message": "Project Supervisor was updated!"}
|
return {"message": "Project Supervisor was updated!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.post("/<int:id>/year-group/<int:year_group_id>/")
|
@bp.post("/copy-project-supervisors-from-last-year-group/<int:year_group_id>/")
|
||||||
@bp.input(ProjectSupervisorYearGroupSchema)
|
|
||||||
@bp.output(MessageSchema, status_code=201)
|
@bp.output(MessageSchema, status_code=201)
|
||||||
def add_project_supervisor_to_year_group(id: int, year_group_id: int, data: dict) -> dict:
|
def copy_project_supervisors_from_last_year_group(year_group_id: int) -> 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(404, f"Not found project supervisor!")
|
|
||||||
|
|
||||||
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
if year_group is None:
|
if year_group is None:
|
||||||
abort(404, "Not found year group!")
|
abort(404, "Not found year group!")
|
||||||
|
|
||||||
ygps = YearGroupProjectSupervisors.query.filter(YearGroupProjectSupervisors.project_supervisor_id == id). \
|
last_year_group = YearGroup.query.filter(YearGroup.mode == year_group.mode). \
|
||||||
filter(YearGroupProjectSupervisors.year_group_id == year_group_id).first()
|
filter(YearGroup.id != year_group_id).filter(YearGroup.created_at < year_group.created_at). \
|
||||||
if ygps is not None:
|
order_by(db.desc(YearGroup.created_at)).first()
|
||||||
abort(400, "Project supervisor is assigned to this year group!")
|
if last_year_group is None:
|
||||||
|
abort(400, "The latest year group doesn't exist!")
|
||||||
|
|
||||||
ygps = YearGroupProjectSupervisors(year_group_id=year_group_id, project_supervisor_id=id,
|
project_supervisors = ProjectSupervisor.query.filter(ProjectSupervisor.year_group_id == last_year_group.id).all()
|
||||||
limit_group=limit_group)
|
current_project_supervisors_email_in_new_year_group = [ps.email for ps in ProjectSupervisor.query.filter(
|
||||||
db.session.add(ygps)
|
ProjectSupervisor.year_group_id == year_group_id).all()]
|
||||||
|
for ps in project_supervisors:
|
||||||
|
if ps.email not in current_project_supervisors_email_in_new_year_group:
|
||||||
|
new_ps = ProjectSupervisor(first_name=ps.first_name, last_name=ps.last_name, email=ps.email,
|
||||||
|
limit_group=ps.limit_group, year_group_id=year_group_id)
|
||||||
|
db.session.add(new_ps)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {"message": "Project Supervisor was added to year group!"}
|
|
||||||
|
|
||||||
|
return {"message": "Project Supervisors was added!"}
|
||||||
@bp.delete("/<int:id>/year-group/<int:year_group_id>/")
|
|
||||||
@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).first()
|
|
||||||
if project_supervisor is None:
|
|
||||||
abort(404, f"Not found project supervisor!")
|
|
||||||
|
|
||||||
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
|
||||||
if year_group is None:
|
|
||||||
abort(404, "Not found year group!")
|
|
||||||
|
|
||||||
db.session.delete(project_supervisor)
|
|
||||||
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).first()
|
|
||||||
if project_supervisor is None:
|
|
||||||
abort(404, f"Not found project supervisor!")
|
|
||||||
|
|
||||||
year_group = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
|
||||||
if year_group is None:
|
|
||||||
abort(404, "Not found year group!")
|
|
||||||
|
|
||||||
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!"}
|
|
||||||
|
@ -6,14 +6,15 @@ from apiflask import APIBlueprint
|
|||||||
from sqlalchemy import or_
|
from sqlalchemy import or_
|
||||||
from flask_sqlalchemy import get_debug_queries
|
from flask_sqlalchemy import get_debug_queries
|
||||||
|
|
||||||
from ...students.models import Student, Group, YearGroup, YearGroupStudents
|
from ...students.models import Student, Group, YearGroup
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, YearGroupInfoQuery, \
|
from ..schemas import StudentSchema, StudentEditSchema, StudentsPaginationSchema, YearGroupInfoQuery, \
|
||||||
StudentCreateSchema, MessageSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema
|
StudentCreateSchema, FileSchema, StudentQuerySchema, StudentListFileDownloaderSchema
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ..utils import parse_csv, generate_csv
|
from ..utils import parse_csv, generate_csv
|
||||||
from ..exceptions import InvalidNameOrTypeHeaderException
|
from ..exceptions import InvalidNameOrTypeHeaderException
|
||||||
from ...base.utils import paginate_models, is_allowed_extensions
|
from ...base.utils import paginate_models, is_allowed_extensions
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("students", __name__, url_prefix="/students")
|
bp = APIBlueprint("students", __name__, url_prefix="/students")
|
||||||
|
|
||||||
@ -40,19 +41,19 @@ def list_students(year_group_id: int, query: dict) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/<int:index>/detail/")
|
@bp.get("/<int:student_id>/detail/")
|
||||||
@bp.output(StudentSchema)
|
@bp.output(StudentSchema)
|
||||||
def detail_student(index: int) -> Student:
|
def detail_student(student_id: int) -> Student:
|
||||||
student = Student.query.filter_by(index=index).first()
|
student = Student.query.filter_by(id=student_id).first()
|
||||||
if student is None:
|
if student is None:
|
||||||
abort(404, "Not found student!")
|
abort(404, "Not found student!")
|
||||||
return student
|
return student
|
||||||
|
|
||||||
|
|
||||||
@bp.delete("/<int:index>/")
|
@bp.delete("/<int:student_id>/")
|
||||||
@bp.output(MessageSchema, status_code=202)
|
@bp.output(MessageSchema, status_code=202)
|
||||||
def delete_student(index: int) -> dict:
|
def delete_student(student_id: int) -> dict:
|
||||||
student = Student.query.filter_by(index=index).first()
|
student = Student.query.filter_by(id=student_id).first()
|
||||||
if student is None:
|
if student is None:
|
||||||
abort(404, "Not found student!")
|
abort(404, "Not found student!")
|
||||||
db.session.delete(student)
|
db.session.delete(student)
|
||||||
@ -60,14 +61,14 @@ def delete_student(index: int) -> dict:
|
|||||||
return {"message": "Student was deleted!"}
|
return {"message": "Student was deleted!"}
|
||||||
|
|
||||||
|
|
||||||
@bp.put("/<int:index>/")
|
@bp.put("/<int:student_id>/")
|
||||||
@bp.input(StudentEditSchema)
|
@bp.input(StudentEditSchema)
|
||||||
@bp.output(MessageSchema)
|
@bp.output(MessageSchema)
|
||||||
def edit_student(index: int, data: dict) -> dict:
|
def edit_student(student_id: int, data: dict) -> dict:
|
||||||
if not data:
|
if not data:
|
||||||
abort(400, 'You have passed empty data!')
|
abort(400, 'You have passed empty data!')
|
||||||
|
|
||||||
student_query = Student.query.filter_by(index=index)
|
student_query = Student.query.filter(Student.id==student_id)
|
||||||
student = student_query.first()
|
student = student_query.first()
|
||||||
|
|
||||||
if student is None:
|
if student is None:
|
||||||
@ -87,24 +88,18 @@ def create_student(data: dict) -> dict:
|
|||||||
yg_id = data['year_group_id']
|
yg_id = data['year_group_id']
|
||||||
del data['year_group_id']
|
del data['year_group_id']
|
||||||
|
|
||||||
student = Student.query.filter(Student.index == index).first()
|
student = Student.query.filter(Student.index == index, Student.year_group_id == yg_id).first()
|
||||||
# if student is not None:
|
if student is not None:
|
||||||
# abort(400, "Student has already exists!")
|
abort(400, "Student has already assigned to this year group!")
|
||||||
if student is None:
|
|
||||||
dummy_email = f'student{randint(1, 300_000)}@gmail.com'
|
|
||||||
student = Student(**data, email=dummy_email)
|
|
||||||
db.session.add(student)
|
|
||||||
|
|
||||||
# add student to the chosen year group
|
# add student to the chosen year group
|
||||||
year_group = YearGroup.query.filter(YearGroup.id == yg_id).first()
|
year_group = YearGroup.query.filter(YearGroup.id == yg_id).first()
|
||||||
if year_group is None:
|
if year_group is None:
|
||||||
abort(404, "Not found year group!")
|
abort(404, "Not found year group!")
|
||||||
if any((year_group.id == yg.id for yg in student.year_groups)):
|
|
||||||
abort(400, "You are assigned to this year group!")
|
|
||||||
|
|
||||||
ygs = YearGroupStudents(student_index=student.index, year_group_id=year_group.id)
|
|
||||||
db.session.add(ygs)
|
|
||||||
|
|
||||||
|
dummy_email = f'student{randint(1, 300_000)}@gmail.com'
|
||||||
|
student = Student(**data, email=dummy_email, year_group_id=yg_id)
|
||||||
|
db.session.add(student)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return {"message": "Student was created!"}
|
return {"message": "Student was created!"}
|
||||||
@ -117,7 +112,7 @@ def create_student(data: dict) -> dict:
|
|||||||
def upload_students(query: dict, file: dict) -> dict:
|
def upload_students(query: dict, file: dict) -> dict:
|
||||||
"""Add only Students to chosen year group if students exist in db and assigned to correct year group,
|
"""Add only Students to chosen year group if students exist in db and assigned to correct year group,
|
||||||
they will be omitted"""
|
they will be omitted"""
|
||||||
year_group_id = query.get('id')
|
year_group_id = query.get('year_group_id')
|
||||||
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
yg = YearGroup.query.filter(YearGroup.id == year_group_id).first()
|
||||||
if yg is None:
|
if yg is None:
|
||||||
abort(404, "Not found year group!")
|
abort(404, "Not found year group!")
|
||||||
@ -125,7 +120,7 @@ def upload_students(query: dict, file: dict) -> dict:
|
|||||||
uploaded_file = file.get('file')
|
uploaded_file = file.get('file')
|
||||||
if uploaded_file and is_allowed_extensions(uploaded_file.filename):
|
if uploaded_file and is_allowed_extensions(uploaded_file.filename):
|
||||||
try:
|
try:
|
||||||
students = parse_csv(uploaded_file)
|
students = parse_csv(uploaded_file, year_group_id)
|
||||||
while True:
|
while True:
|
||||||
sliced_students = islice(students, 5)
|
sliced_students = islice(students, 5)
|
||||||
list_of_students = list(sliced_students)
|
list_of_students = list(sliced_students)
|
||||||
@ -133,25 +128,13 @@ def upload_students(query: dict, file: dict) -> dict:
|
|||||||
if len(list_of_students) == 0:
|
if len(list_of_students) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
students_in_db = Student.query.filter(or_(Student.index == s.index for s in list_of_students)).all()
|
students_in_db = Student.query.filter(or_(Student.index == s.index for s in list_of_students)).\
|
||||||
students_in_db_and_assigned_to_year_group = Student.query.join(YearGroupStudents, isouter=True). \
|
filter(Student.year_group_id==year_group_id).all()
|
||||||
filter(YearGroupStudents.year_group_id == year_group_id). \
|
|
||||||
filter(or_(Student.index == s.index for s in list_of_students)).all()
|
|
||||||
|
|
||||||
student_index_in_db = [s.index for s in students_in_db]
|
student_index_in_db = [s.index for s in students_in_db]
|
||||||
student_index_in_year_group = [s.index for s in students_in_db_and_assigned_to_year_group]
|
|
||||||
students_in_db_and_not_assigned_to_year_group = list(
|
|
||||||
filter(lambda s: s.index not in student_index_in_year_group, students_in_db))
|
|
||||||
|
|
||||||
students_not_exists_in_db = list(filter(lambda s: s.index not in student_index_in_db, list_of_students))
|
students_not_exists_in_db = list(filter(lambda s: s.index not in student_index_in_db, list_of_students))
|
||||||
db.session.add_all(students_not_exists_in_db)
|
db.session.add_all(students_not_exists_in_db)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
ygs = [YearGroupStudents(year_group_id=year_group_id, student_index=student.index) for student in
|
|
||||||
students_in_db_and_not_assigned_to_year_group + students_not_exists_in_db]
|
|
||||||
db.session.add_all(ygs)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
except InvalidNameOrTypeHeaderException:
|
except InvalidNameOrTypeHeaderException:
|
||||||
abort(400, "Invalid format of csv file!")
|
abort(400, "Invalid format of csv file!")
|
||||||
else:
|
else:
|
||||||
@ -169,7 +152,7 @@ def download_students(query: dict) -> Response:
|
|||||||
join(ProjectSupervisor).all()
|
join(ProjectSupervisor).all()
|
||||||
|
|
||||||
if len(students_and_groups) == 0:
|
if len(students_and_groups) == 0:
|
||||||
abort(404, "Not found students, which are assigned to group!")
|
abort(404, "Not found students!")
|
||||||
|
|
||||||
csv_file = generate_csv(students_and_groups)
|
csv_file = generate_csv(students_and_groups)
|
||||||
response = Response(csv_file, mimetype='text/csv')
|
response = Response(csv_file, mimetype='text/csv')
|
||||||
|
@ -2,9 +2,10 @@ from flask import abort
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
|
|
||||||
from ...students.models import YearGroup
|
from ...students.models import YearGroup
|
||||||
from ..schemas import YearGroupSchema, MessageSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
from ..schemas import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ...base.utils import paginate_models
|
from ...base.utils import paginate_models
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("year_group", __name__, url_prefix="/year-group")
|
bp = APIBlueprint("year_group", __name__, url_prefix="/year-group")
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ from .examination_schedule import ExaminationScheduleSchema, ExaminationSchedule
|
|||||||
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema
|
ExaminationSchedulesPaginationSchema, ExaminationSchedulesQuerySchema, WorkloadSchema
|
||||||
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema, GroupIdSchema
|
from .groups import GroupQuerySchema, GroupsPaginationSchema, GroupCreateSchema, GroupEditSchema, GroupIdSchema
|
||||||
from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \
|
from .project_supervisor import ProjectSupervisorQuerySchema, ProjectSupervisorsPaginationSchema, \
|
||||||
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema, ProjectSupervisorYearGroupSchema
|
ProjectSupervisorCreateSchema, ProjectSupervisorEditSchema
|
||||||
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
|
from .students import ProjectSupervisorSchema, GroupSchema, StudentSchema, StudentsPaginationSchema, \
|
||||||
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageSchema, FileSchema, \
|
StudentListFileDownloaderSchema, StudentCreateSchema, StudentEditSchema, MessageWithIdSchema, FileSchema, \
|
||||||
StudentQuerySchema, YearGroupInfoQuery, DetailGroupSchema
|
StudentQuerySchema, YearGroupInfoQuery, DetailGroupSchema
|
||||||
from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
from .year_group import YearGroupSchema, YearGroupPaginationSchema, YearGroupQuerySchema
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from marshmallow import Schema, fields, validate
|
from marshmallow import Schema, fields, validate
|
||||||
|
|
||||||
from ..validators import validate_index
|
from ..validators import validate_index
|
||||||
from .students import GroupSchema, StudentSchema
|
from .students import GroupSchema
|
||||||
|
|
||||||
|
|
||||||
class GroupQuerySchema(Schema):
|
class GroupQuerySchema(Schema):
|
||||||
@ -18,13 +18,13 @@ class GroupsPaginationSchema(Schema):
|
|||||||
class GroupCreateSchema(Schema):
|
class GroupCreateSchema(Schema):
|
||||||
name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
||||||
project_supervisor_id = fields.Integer(required=True)
|
project_supervisor_id = fields.Integer(required=True)
|
||||||
students = fields.List(fields.Integer(validate=validate_index, required=True))
|
students = fields.List(fields.Integer(required=True))
|
||||||
|
|
||||||
|
|
||||||
class GroupEditSchema(Schema):
|
class GroupEditSchema(Schema):
|
||||||
name = fields.Str(validate=validate.Length(min=1, max=255))
|
name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
project_supervisor_id = fields.Integer()
|
project_supervisor_id = fields.Integer()
|
||||||
students = fields.List(fields.Integer(validate=validate_index))
|
students = fields.List(fields.Integer())
|
||||||
|
|
||||||
|
|
||||||
class GroupIdSchema(Schema):
|
class GroupIdSchema(Schema):
|
||||||
|
@ -20,13 +20,11 @@ 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), validate.Email()], required=True)
|
email = fields.Str(validate=[validate.Length(min=1, max=255), validate.Email()], required=True)
|
||||||
|
limit_group = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorEditSchema(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))
|
||||||
last_name = fields.Str(validate=validate.Length(min=1, max=255), required=True)
|
last_name = fields.Str(validate=validate.Length(min=1, max=255))
|
||||||
email = fields.Str(validate=[validate.Length(min=0, max=255), validate.Email()], required=True)
|
email = fields.Str(validate=[validate.Length(min=0, max=255), validate.Email()])
|
||||||
|
limit_group = fields.Integer()
|
||||||
|
|
||||||
class ProjectSupervisorYearGroupSchema(Schema):
|
|
||||||
limit_group = fields.Integer(required=True)
|
|
@ -20,7 +20,7 @@ class GroupSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
|
|
||||||
|
|
||||||
class StudentSchema(ma.SQLAlchemyAutoSchema):
|
class StudentSchema(ma.SQLAlchemyAutoSchema):
|
||||||
groups = fields.List(fields.Nested(GroupSchema))
|
group = fields.Nested(GroupSchema)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Student
|
model = Student
|
||||||
@ -38,7 +38,6 @@ class StudentListFileDownloaderSchema(ma.Schema):
|
|||||||
class StudentCreateSchema(ma.Schema):
|
class StudentCreateSchema(ma.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)
|
||||||
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)
|
||||||
year_group_id = fields.Integer()
|
year_group_id = fields.Integer()
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ class StudentEditSchema(ma.Schema):
|
|||||||
index = fields.Integer(validate=validate_index)
|
index = fields.Integer(validate=validate_index)
|
||||||
|
|
||||||
|
|
||||||
class MessageSchema(ma.Schema):
|
class MessageWithIdSchema(ma.Schema):
|
||||||
message = fields.Str(required=True)
|
message = fields.Str(required=True)
|
||||||
id = fields.Str(required=False)
|
id = fields.Str(required=False)
|
||||||
|
|
||||||
@ -68,7 +67,7 @@ class StudentQuerySchema(ma.Schema):
|
|||||||
|
|
||||||
|
|
||||||
class YearGroupInfoQuery(Schema):
|
class YearGroupInfoQuery(Schema):
|
||||||
id = fields.Integer(required=True)
|
year_group_id = fields.Integer(required=True)
|
||||||
|
|
||||||
class DetailGroupSchema(ma.SQLAlchemyAutoSchema):
|
class DetailGroupSchema(ma.SQLAlchemyAutoSchema):
|
||||||
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
project_supervisor = fields.Nested(ProjectSupervisorSchema)
|
||||||
|
@ -24,42 +24,31 @@ from ..examination_schedule.models import TermOfDefence
|
|||||||
|
|
||||||
def check_columns(df: pd.DataFrame) -> bool:
|
def check_columns(df: pd.DataFrame) -> bool:
|
||||||
headers = set(df.keys().values)
|
headers = set(df.keys().values)
|
||||||
columns = ['NAZWISKO', 'IMIE', 'INDEKS', 'PESEL', 'EMAIL']
|
column_names = ['NAZWISKO', 'IMIE', 'INDEKS', 'EMAIL']
|
||||||
|
column_types = ['object', 'object', 'int', 'object']
|
||||||
if len(headers - set(columns)) != 0:
|
return all((column_name in headers for column_name in column_names)) and \
|
||||||
return False
|
all((str(df.dtypes[column_name]).startswith(column_type) for column_name, column_type in
|
||||||
|
zip(column_names, column_types)))
|
||||||
flag = True
|
|
||||||
col_types = ['object', 'object', 'int', 'int64', 'object']
|
|
||||||
|
|
||||||
for name, col_type in zip(columns, col_types):
|
|
||||||
if not str(df.dtypes[name]).startswith(col_type):
|
|
||||||
flag = False
|
|
||||||
break
|
|
||||||
|
|
||||||
return flag
|
|
||||||
|
|
||||||
|
|
||||||
def parse_csv(file: Union[FileStorage, TextIO]) -> Generator[Student, Any, None]:
|
def parse_csv(file: Union[FileStorage, TextIO], year_group_id: int) -> Generator[Student, Any, None]:
|
||||||
df = pd.read_csv(file)
|
df = pd.read_csv(file)
|
||||||
# raise Exception(df.to_string())
|
|
||||||
if not check_columns(df):
|
if not check_columns(df):
|
||||||
raise InvalidNameOrTypeHeaderException
|
raise InvalidNameOrTypeHeaderException
|
||||||
|
|
||||||
students = (Student(last_name=dict(item.items())['NAZWISKO'],
|
students = (Student(last_name=dict(item.items())['NAZWISKO'],
|
||||||
first_name=dict(item.items())['IMIE'],
|
first_name=dict(item.items())['IMIE'],
|
||||||
index=dict(item.items())['INDEKS'],
|
index=dict(item.items())['INDEKS'],
|
||||||
pesel=str(int(dict(item.items())['PESEL'])) if not pd.isna(
|
email=dict(item.items())['EMAIL'],
|
||||||
dict(item.items())['PESEL']) else None,
|
year_group_id=year_group_id)
|
||||||
email=dict(item.items())['EMAIL'])
|
|
||||||
for _, item in df.iterrows())
|
for _, item in df.iterrows())
|
||||||
|
|
||||||
return students
|
return students
|
||||||
|
|
||||||
|
|
||||||
def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
|
def generate_csv(students_and_groups: List[Tuple[Student, Group]]) -> str:
|
||||||
headers = ['PESEL', 'INDEKS', 'IMIE', 'NAZWISKO', 'EMAIL', 'CDYD_KOD', 'PRZ_KOD', 'TZAJ_KOD', 'GR_NR', 'PRG_KOD']
|
headers = ['INDEKS', 'IMIE', 'NAZWISKO', 'EMAIL', 'CDYD_KOD', 'PRZ_KOD', 'TZAJ_KOD', 'GR_NR', 'PRG_KOD']
|
||||||
data = [(student.pesel, student.index, student.first_name, student.last_name, student.email,
|
data = [(student.index, student.first_name, student.last_name, student.email,
|
||||||
group.cdyd_kod, group.prz_kod, group.tzaj_kod, group.project_supervisor_id,
|
group.cdyd_kod, group.prz_kod, group.tzaj_kod, group.project_supervisor_id,
|
||||||
None) for student, group in students_and_groups]
|
None) for student, group in students_and_groups]
|
||||||
dataframe = defaultdict(list)
|
dataframe = defaultdict(list)
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from apiflask import APIFlask
|
from apiflask import APIFlask
|
||||||
from werkzeug.exceptions import RequestEntityTooLarge, HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
|
|
||||||
def request_entity_too_large(error: RequestEntityTooLarge) -> Tuple[dict, int]:
|
|
||||||
return {'error': 'File too large!'}, 413
|
|
||||||
|
|
||||||
|
|
||||||
def register_error_handlers(app: APIFlask):
|
def register_error_handlers(app: APIFlask):
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
from factory import alchemy, Sequence
|
|
||||||
from factory.faker import Faker
|
|
||||||
from factory.fuzzy import FuzzyInteger, FuzzyChoice
|
|
||||||
|
|
||||||
from .dependencies import db
|
|
||||||
from .students.models import Student, Group
|
|
||||||
from .project_supervisor.models import ProjectSupervisor
|
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorFactory(alchemy.SQLAlchemyModelFactory):
|
|
||||||
class Meta:
|
|
||||||
model = ProjectSupervisor
|
|
||||||
sqlalchemy_session = db.session
|
|
||||||
|
|
||||||
first_name = Faker('first_name')
|
|
||||||
last_name = Faker('last_name')
|
|
||||||
email = Faker('email')
|
|
||||||
limit_group = 4 # FuzzyInteger(3, 5)
|
|
||||||
count_groups = 4
|
|
||||||
mode = 0
|
|
||||||
|
|
||||||
|
|
||||||
class GroupFactory(alchemy.SQLAlchemyModelFactory):
|
|
||||||
class Meta:
|
|
||||||
model = Group
|
|
||||||
sqlalchemy_session = db.session
|
|
||||||
|
|
||||||
name = Sequence(lambda n: f'Group-{n}')
|
|
||||||
points_for_first_term = FuzzyInteger(1, 5)
|
|
||||||
points_for_second_term = FuzzyInteger(1, 5)
|
|
||||||
# project_supervisor = RelatedFactory(ProjectSupervisorFactory, 'project_supervisor')
|
|
||||||
|
|
||||||
|
|
||||||
class StudentFactory(alchemy.SQLAlchemyModelFactory):
|
|
||||||
class Meta:
|
|
||||||
model = Student
|
|
||||||
sqlalchemy_session = db.session
|
|
||||||
|
|
||||||
first_name = Faker('first_name')
|
|
||||||
last_name = Faker('last_name')
|
|
||||||
email = Faker('email')
|
|
||||||
index = Sequence(lambda n: 400_000 + n)
|
|
||||||
# group = RelatedFactory(GroupFactory)
|
|
||||||
mode = FuzzyChoice([True, False])
|
|
@ -6,18 +6,12 @@ from ..base.utils import order_by_column_name
|
|||||||
from ..students.models import YearGroup
|
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"
|
||||||
|
|
||||||
year_groups = db.relationship('YearGroupProjectSupervisors', lazy=True)
|
limit_group = db.Column(db.Integer, default=3, nullable=False)
|
||||||
|
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||||
|
year_group = db.relationship('YearGroup', backref='project_supervisors')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int = None,
|
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int = None,
|
||||||
@ -27,8 +21,8 @@ class ProjectSupervisor(Base, Person):
|
|||||||
project_supervisors_query = cls.query
|
project_supervisors_query = cls.query
|
||||||
|
|
||||||
if year_group_id is not None:
|
if year_group_id is not None:
|
||||||
project_supervisors_query = project_supervisors_query.join(YearGroupProjectSupervisors). \
|
project_supervisors_query = project_supervisors_query. \
|
||||||
filter(YearGroupProjectSupervisors.year_group_id == year_group_id)
|
filter(ProjectSupervisor.year_group_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(
|
||||||
|
@ -3,11 +3,12 @@ from datetime import datetime
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from sqlalchemy import and_, or_
|
from sqlalchemy import and_, or_
|
||||||
from ..schemas import MessageSchema, TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
|
from ..schemas import TimeAvailabilityCreateSchema, TemporaryProjectSupervisorSchema, \
|
||||||
ListOfFreeTimesSchema, ListOfTermOfDefenceSchema
|
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
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
@ -3,10 +3,11 @@ from flask import abort
|
|||||||
|
|
||||||
from ...dependencies import db
|
from ...dependencies import db
|
||||||
from ..models import ProjectSupervisor
|
from ..models import ProjectSupervisor
|
||||||
from ..schemas import ProjectSupervisorTermQuerySchema, MessageSchema, TemporaryProjectSupervisorSchema
|
from ..schemas import ProjectSupervisorTermQuerySchema, TemporaryProjectSupervisorSchema
|
||||||
from ...students.schemas import ProjectGradeSheetDetailFirstTermSchema, ProjectGradeSheetDetailSecondTermSchema, \
|
from ...students.schemas import ProjectGradeSheetDetailFirstTermSchema, ProjectGradeSheetDetailSecondTermSchema, \
|
||||||
ProjectGradeSheetEditFirstTermSchema, ProjectGradeSheetEditSecondTermSchema
|
ProjectGradeSheetEditFirstTermSchema, ProjectGradeSheetEditSecondTermSchema
|
||||||
from ...students.models import Group, ProjectGradeSheet
|
from ...students.models import Group, ProjectGradeSheet
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("project_grade_sheet_for_project_supervisor", __name__, url_prefix="/project-grade-sheet")
|
bp = APIBlueprint("project_grade_sheet_for_project_supervisor", __name__, url_prefix="/project-grade-sheet")
|
||||||
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
from marshmallow import fields, validate, Schema
|
from marshmallow import fields, validate, Schema
|
||||||
|
|
||||||
|
|
||||||
class MessageSchema(Schema):
|
|
||||||
message = fields.Str()
|
|
||||||
|
|
||||||
|
|
||||||
class FreeTimeSchema(Schema):
|
class FreeTimeSchema(Schema):
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
start_date = fields.DateTime(required=True)
|
start_date = fields.DateTime(required=True)
|
||||||
@ -29,6 +25,7 @@ class TimeAvailabilityCreateSchema(Schema):
|
|||||||
class TemporaryProjectSupervisorSchema(Schema):
|
class TemporaryProjectSupervisorSchema(Schema):
|
||||||
id = fields.Integer(required=True)
|
id = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorTermQuerySchema(Schema):
|
class ProjectSupervisorTermQuerySchema(Schema):
|
||||||
id = fields.Integer(required=True)
|
id = fields.Integer(required=True)
|
||||||
term = fields.Integer(required=True, validate=validate.OneOf([1, 2]))
|
term = fields.Integer(required=True, validate=validate.OneOf([1, 2]))
|
||||||
|
@ -8,20 +8,12 @@ from ..base.utils import order_by_column_name
|
|||||||
from ..examination_schedule.models import TermOfDefence
|
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):
|
class YearGroup(Base):
|
||||||
__tablename__ = 'year_groups'
|
__tablename__ = 'year_groups'
|
||||||
|
|
||||||
name = db.Column(db.String(50), nullable=False)
|
name = db.Column(db.String(50), nullable=False)
|
||||||
mode = db.Column(db.String(1), nullable=False)
|
mode = db.Column(db.String(1), nullable=False)
|
||||||
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
||||||
students = db.relationship("YearGroupStudents", lazy='joined')
|
|
||||||
|
|
||||||
__table__args = (
|
__table__args = (
|
||||||
db.UniqueConstraint('name', 'mode', name='uc_name_mode_year_group')
|
db.UniqueConstraint('name', 'mode', name='uc_name_mode_year_group')
|
||||||
@ -30,7 +22,7 @@ class YearGroup(Base):
|
|||||||
|
|
||||||
students_groups = db.Table('students_groups',
|
students_groups = db.Table('students_groups',
|
||||||
db.Column('group_id', db.ForeignKey('groups.id'), nullable=False),
|
db.Column('group_id', db.ForeignKey('groups.id'), nullable=False),
|
||||||
db.Column('student_index', db.ForeignKey('students.index'), nullable=False))
|
db.Column('student_id', db.ForeignKey('students.id'), nullable=False))
|
||||||
|
|
||||||
|
|
||||||
class Group(Base):
|
class Group(Base):
|
||||||
@ -41,12 +33,12 @@ class Group(Base):
|
|||||||
prz_kod = db.Column(db.String(60), default='06-DPRILI0')
|
prz_kod = db.Column(db.String(60), default='06-DPRILI0')
|
||||||
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='joined')
|
project_supervisor = db.relationship('ProjectSupervisor', backref='groups')
|
||||||
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||||
year_group = db.relationship('YearGroup', backref='groups', lazy='joined')
|
year_group = db.relationship('YearGroup', backref='groups', lazy='joined')
|
||||||
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)
|
||||||
students = db.relationship('Student', secondary=students_groups, back_populates='groups', lazy='joined')
|
students = db.relationship('Student', secondary=students_groups, back_populates='groups')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_by_name(cls, year_group_id: int, search_name: str = None) -> BaseQuery:
|
def search_by_name(cls, year_group_id: int, search_name: str = None) -> BaseQuery:
|
||||||
@ -62,7 +54,7 @@ class ProjectGradeSheet(Base):
|
|||||||
__tablename__ = 'project_grade_sheets'
|
__tablename__ = 'project_grade_sheets'
|
||||||
|
|
||||||
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='project_grade_sheet', uselist=False, lazy='joined')
|
group = db.relationship('Group', backref='project_grade_sheet', uselist=False)
|
||||||
|
|
||||||
presentation_required_content_1 = db.Column(db.Integer, default=0)
|
presentation_required_content_1 = db.Column(db.Integer, default=0)
|
||||||
presentation_required_content_2 = db.Column(db.Integer, default=0)
|
presentation_required_content_2 = db.Column(db.Integer, default=0)
|
||||||
@ -125,20 +117,19 @@ class ProjectGradeSheet(Base):
|
|||||||
products_project_technology_2 = db.Column(db.Integer, default=0)
|
products_project_technology_2 = db.Column(db.Integer, default=0)
|
||||||
|
|
||||||
|
|
||||||
class Student(Person):
|
class Student(Base, Person):
|
||||||
__tablename__ = "students"
|
__tablename__ = "students"
|
||||||
|
|
||||||
pesel = db.Column(db.String(11), default='')
|
index = db.Column(db.Integer, nullable=False)
|
||||||
index = db.Column(db.Integer, primary_key=True)
|
groups = db.relationship('Group', secondary=students_groups, back_populates='students')
|
||||||
groups = db.relationship('Group', secondary=students_groups, back_populates='students', lazy='joined')
|
year_group_id = db.Column(db.Integer, db.ForeignKey('year_groups.id'))
|
||||||
year_groups = db.relationship("YearGroupStudents", lazy='joined')
|
year_group = db.relationship('YearGroup', backref='students')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def search_by_fullname_and_mode_and_order_by_first_name_or_last_name(cls, year_group_id: int, 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,
|
||||||
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.join(YearGroupStudents, isouter=True). \
|
student_query = cls.query.filter(Student.year_group_id == year_group_id)
|
||||||
filter(YearGroupStudents.year_group_id == year_group_id)
|
|
||||||
|
|
||||||
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}%'))
|
||||||
|
@ -3,11 +3,9 @@ from flask import Blueprint
|
|||||||
from .enrollments import bp as enrollments_bp
|
from .enrollments import bp as enrollments_bp
|
||||||
from .project_grade_sheet import bp as project_grade_sheet_bp
|
from .project_grade_sheet import bp as project_grade_sheet_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(enrollments_bp)
|
bp.register_blueprint(enrollments_bp)
|
||||||
bp.register_blueprint(project_grade_sheet_bp)
|
bp.register_blueprint(project_grade_sheet_bp)
|
||||||
bp.register_blueprint(registrations_bp)
|
bp.register_blueprint(registrations_bp)
|
||||||
bp.register_blueprint(year_group_bp)
|
|
||||||
|
@ -3,12 +3,13 @@ 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 TemporaryStudentSchema, ExaminationScheduleListSchema, \
|
||||||
TermOfDefenceStudentListSchema
|
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
|
||||||
from ...project_supervisor.models import ProjectSupervisor
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
|
from ...base.schemas import MessageSchema
|
||||||
|
|
||||||
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
bp = APIBlueprint("enrollments", __name__, url_prefix="/")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from apiflask import APIBlueprint
|
from apiflask import APIBlueprint
|
||||||
|
|
||||||
from ...project_supervisor.models import ProjectSupervisor, YearGroupProjectSupervisors
|
from ...project_supervisor.models import ProjectSupervisor
|
||||||
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
|
||||||
@ -16,12 +16,11 @@ def list_available_groups(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')
|
||||||
|
|
||||||
available_groups = (YearGroupProjectSupervisors.limit_group - db.func.count(Group.id))
|
available_groups = (ProjectSupervisor.limit_group - db.func.count(Group.id))
|
||||||
ps_query = db.session. \
|
ps_query = db.session. \
|
||||||
query(ProjectSupervisor, available_groups). \
|
query(ProjectSupervisor, available_groups). \
|
||||||
join(Group, isouter=True). \
|
join(Group, isouter=True). \
|
||||||
join(YearGroupProjectSupervisors, isouter=True). \
|
filter(ProjectSupervisor.year_group_id == year_group_id).\
|
||||||
filter(YearGroupProjectSupervisors.year_group_id == year_group_id).\
|
|
||||||
group_by(ProjectSupervisor.id)
|
group_by(ProjectSupervisor.id)
|
||||||
|
|
||||||
data = paginate_models(page, ps_query, per_page)
|
data = paginate_models(page, ps_query, per_page)
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
from apiflask import APIBlueprint
|
|
||||||
from flask import abort
|
|
||||||
|
|
||||||
from ...students.models import YearGroup, YearGroupStudents
|
|
||||||
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 = db.session.query(YearGroup).join(YearGroupStudents, isouter=True). \
|
|
||||||
filter(YearGroupStudents.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']
|
|
||||||
}
|
|
@ -24,10 +24,6 @@ class TemporaryStudentSchema(Schema):
|
|||||||
student_index = fields.Integer(required=True)
|
student_index = fields.Integer(required=True)
|
||||||
|
|
||||||
|
|
||||||
class MessageSchema(Schema):
|
|
||||||
message = fields.Str()
|
|
||||||
|
|
||||||
|
|
||||||
class ExaminationScheduleSchema(Schema):
|
class ExaminationScheduleSchema(Schema):
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
title = fields.Str()
|
title = fields.Str()
|
||||||
@ -51,39 +47,26 @@ class TermOfDefenceStudentItemSchema(Schema):
|
|||||||
end_date = fields.DateTime()
|
end_date = fields.DateTime()
|
||||||
members_of_committee = fields.List(fields.Nested(ProjectSupervisorCommitteeSchema))
|
members_of_committee = fields.List(fields.Nested(ProjectSupervisorCommitteeSchema))
|
||||||
|
|
||||||
|
|
||||||
class StudentDataItemSchema(Schema):
|
class StudentDataItemSchema(Schema):
|
||||||
index = fields.Integer()
|
index = fields.Integer()
|
||||||
first_name = fields.Str()
|
first_name = fields.Str()
|
||||||
last_name = fields.Str()
|
last_name = fields.Str()
|
||||||
|
|
||||||
|
|
||||||
class GroupDataItemSchema(Schema):
|
class GroupDataItemSchema(Schema):
|
||||||
name = fields.Str()
|
name = fields.Str()
|
||||||
students = fields.List(fields.Nested(StudentDataItemSchema))
|
students = fields.List(fields.Nested(StudentDataItemSchema))
|
||||||
|
|
||||||
|
|
||||||
class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceStudentItemSchema):
|
class AssignedGroupToTermOfDefenceItemSchema(TermOfDefenceStudentItemSchema):
|
||||||
group = fields.Nested(GroupDataItemSchema)
|
group = fields.Nested(GroupDataItemSchema)
|
||||||
|
|
||||||
|
|
||||||
class TermOfDefenceStudentListSchema(Schema):
|
class TermOfDefenceStudentListSchema(Schema):
|
||||||
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
term_of_defences = fields.List(fields.Nested(AssignedGroupToTermOfDefenceItemSchema))
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
class StudentIndexQueryTempSchema(Schema):
|
class StudentIndexQueryTempSchema(Schema):
|
||||||
index = fields.Integer(required=True) # it will be removed
|
index = fields.Integer(required=True) # it will be removed
|
||||||
term = fields.Integer(required=True, validate=validate.OneOf([1, 2]))
|
term = fields.Integer(required=True, validate=validate.OneOf([1, 2]))
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"""empty message
|
"""empty message
|
||||||
|
|
||||||
Revision ID: b3003ddd0564
|
Revision ID: 3fd120fc5e12
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2023-01-03 18:37:53.103562
|
Create Date: 2023-01-14 00:03:06.327441
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = 'b3003ddd0564'
|
revision = '3fd120fc5e12'
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -18,27 +18,6 @@ depends_on = None
|
|||||||
|
|
||||||
def upgrade():
|
def upgrade():
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### 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('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.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('year_groups',
|
op.create_table('year_groups',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
sa.Column('name', sa.String(length=50), nullable=False),
|
sa.Column('name', sa.String(length=50), nullable=False),
|
||||||
@ -59,6 +38,32 @@ def upgrade():
|
|||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
sa.UniqueConstraint('title')
|
sa.UniqueConstraint('title')
|
||||||
)
|
)
|
||||||
|
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=False),
|
||||||
|
sa.Column('limit_group', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('year_group_id', sa.Integer(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
op.create_index(op.f('ix_project_supervisors_email'), 'project_supervisors', ['email'], unique=False)
|
||||||
|
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('students',
|
||||||
|
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=False),
|
||||||
|
sa.Column('index', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('year_group_id', sa.Integer(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
op.create_index(op.f('ix_students_email'), 'students', ['email'], unique=False)
|
||||||
|
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('groups',
|
op.create_table('groups',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
sa.Column('name', sa.String(length=60), nullable=False),
|
sa.Column('name', sa.String(length=60), nullable=False),
|
||||||
@ -73,21 +78,14 @@ def upgrade():
|
|||||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
||||||
sa.PrimaryKeyConstraint('id')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('year_group_project_supervisors',
|
op.create_table('temporary_availabilities',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
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.Column('project_supervisor_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('year_group_id', sa.Integer(), nullable=False),
|
sa.ForeignKeyConstraint(['examination_schedule_id'], ['examination_schedules.id'], ),
|
||||||
sa.Column('limit_group', sa.Integer(), nullable=False),
|
|
||||||
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
|
sa.ForeignKeyConstraint(['project_supervisor_id'], ['project_supervisors.id'], ),
|
||||||
sa.ForeignKeyConstraint(['year_group_id'], ['year_groups.id'], ),
|
|
||||||
sa.PrimaryKeyConstraint('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')
|
sa.PrimaryKeyConstraint('id')
|
||||||
)
|
)
|
||||||
op.create_table('project_grade_sheets',
|
op.create_table('project_grade_sheets',
|
||||||
@ -154,19 +152,9 @@ def upgrade():
|
|||||||
)
|
)
|
||||||
op.create_table('students_groups',
|
op.create_table('students_groups',
|
||||||
sa.Column('group_id', sa.Integer(), nullable=False),
|
sa.Column('group_id', sa.Integer(), nullable=False),
|
||||||
sa.Column('student_index', sa.Integer(), nullable=False),
|
sa.Column('student_id', sa.Integer(), nullable=False),
|
||||||
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
sa.ForeignKeyConstraint(['group_id'], ['groups.id'], ),
|
||||||
sa.ForeignKeyConstraint(['student_index'], ['students.index'], )
|
sa.ForeignKeyConstraint(['student_id'], ['students.id'], )
|
||||||
)
|
|
||||||
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',
|
op.create_table('term_of_defences',
|
||||||
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
|
||||||
@ -191,18 +179,18 @@ def downgrade():
|
|||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.drop_table('committees')
|
op.drop_table('committees')
|
||||||
op.drop_table('term_of_defences')
|
op.drop_table('term_of_defences')
|
||||||
op.drop_table('temporary_availabilities')
|
|
||||||
op.drop_table('students_groups')
|
op.drop_table('students_groups')
|
||||||
op.drop_table('project_grade_sheets')
|
op.drop_table('project_grade_sheets')
|
||||||
op.drop_table('year_group_students')
|
op.drop_table('temporary_availabilities')
|
||||||
op.drop_table('year_group_project_supervisors')
|
|
||||||
op.drop_table('groups')
|
op.drop_table('groups')
|
||||||
op.drop_table('examination_schedules')
|
|
||||||
op.drop_table('year_groups')
|
|
||||||
op.drop_index(op.f('ix_students_last_name'), table_name='students')
|
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_index(op.f('ix_students_first_name'), table_name='students')
|
||||||
|
op.drop_index(op.f('ix_students_email'), table_name='students')
|
||||||
op.drop_table('students')
|
op.drop_table('students')
|
||||||
op.drop_index(op.f('ix_project_supervisors_last_name'), table_name='project_supervisors')
|
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_index(op.f('ix_project_supervisors_first_name'), table_name='project_supervisors')
|
||||||
|
op.drop_index(op.f('ix_project_supervisors_email'), table_name='project_supervisors')
|
||||||
op.drop_table('project_supervisors')
|
op.drop_table('project_supervisors')
|
||||||
|
op.drop_table('examination_schedules')
|
||||||
|
op.drop_table('year_groups')
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
Loading…
Reference in New Issue
Block a user