From 191c68acf44dd203f8050f973084d8e4248cb1a8 Mon Sep 17 00:00:00 2001 From: dominik24c Date: Mon, 16 Jan 2023 01:12:15 +0100 Subject: [PATCH] update Group model - add grades field, add set grade for group endpoint for coordinator view --- backend/app/coordinator/routes/groups.py | 28 +++++- backend/app/coordinator/schemas/groups.py | 5 + backend/app/coordinator/utils.py | 95 +++++++++++-------- .../query/project_grade_sheet.py | 6 +- backend/app/students/models.py | 2 + .../{e0e58661131a_.py => 5f2f440d05e2_.py} | 8 +- 6 files changed, 93 insertions(+), 51 deletions(-) rename backend/migrations/versions/{e0e58661131a_.py => 5f2f440d05e2_.py} (98%) diff --git a/backend/app/coordinator/routes/groups.py b/backend/app/coordinator/routes/groups.py index d6efeca..4a26590 100644 --- a/backend/app/coordinator/routes/groups.py +++ b/backend/app/coordinator/routes/groups.py @@ -10,10 +10,11 @@ from ..schemas.groups import ( GroupCreateSchema, GroupEditSchema, GroupQuerySchema, + GroupSetGradeSchema, GroupsPaginationSchema, ) from ..schemas.students import DetailGroupSchema -from ..utils import attach_points_for_first_and_second_term_to_group_models +from ..utils import attach_grade_to_group_models bp = APIBlueprint("groups", __name__, url_prefix="/groups") @@ -28,10 +29,8 @@ def list_groups(year_group_id: int, query: dict) -> dict: groups_query = Group.search_by_name(year_group_id, search_name) data = paginate_models(page, groups_query, per_page) - items = data["items"] - attach_points_for_first_and_second_term_to_group_models(items) - + attach_grade_to_group_models(items) return {"groups": items, "max_pages": data["max_pages"]} @@ -93,7 +92,7 @@ def detail_group(group_id: int) -> Group: group = Group.query.filter_by(id=group_id).first() if group is None: abort(404, "Not found group!") - attach_points_for_first_and_second_term_to_group_models([group]) + attach_grade_to_group_models([group]) return group @@ -146,3 +145,22 @@ def edit_group(group_id: int, data: dict) -> dict: db.session.commit() return {"message": "Group was updated!"} + + +@bp.put("//set-grades/") +@bp.input(GroupSetGradeSchema) +@bp.output(MessageSchema) +def set_grade_for_group(group_id: int, data: dict) -> dict: + if not data: + abort(400, "You have passed empty data!") + + group_query = Group.query.filter_by(id=group_id) + group = group_query.first() + + if group is None: + abort(404, "Not found group!") + + group_query.update(data) + db.session.commit() + + return {"message": "Grade was updated!"} diff --git a/backend/app/coordinator/schemas/groups.py b/backend/app/coordinator/schemas/groups.py index 65d3588..3ef1a3d 100644 --- a/backend/app/coordinator/schemas/groups.py +++ b/backend/app/coordinator/schemas/groups.py @@ -28,3 +28,8 @@ class GroupEditSchema(Schema): class GroupIdSchema(Schema): group_id = fields.Integer(required=True) + + +class GroupSetGradeSchema(Schema): + grade_for_first_term = fields.Float() + grade_for_second_term = fields.Float() diff --git a/backend/app/coordinator/utils.py b/backend/app/coordinator/utils.py index 7872b68..2d352dd 100644 --- a/backend/app/coordinator/utils.py +++ b/backend/app/coordinator/utils.py @@ -272,52 +272,63 @@ def grade_in_percentage(term_key: str, term_points: dict) -> str: def calculate_points_for_both_terms( - weights: dict, project_grade_sheets: List[ProjectGradeSheet] -) -> list: - terms = [] - for pgs in project_grade_sheets: - if pgs is None: - terms.append((0, 0)) - continue - first_term_points = { - "presentation": {"gained_points": 0, "all_points": 0}, - "documentation": {"gained_points": 0, "all_points": 0}, - "group_work": {"gained_points": 0, "all_points": 0}, - "product_project": {"gained_points": 0, "all_points": 0}, - } + weights: dict, project_grade_sheet: ProjectGradeSheet +) -> Tuple[float, float]: + if project_grade_sheet is None: + return 0.0, 0.0 + first_term_points = { + "presentation": {"gained_points": 0, "all_points": 0}, + "documentation": {"gained_points": 0, "all_points": 0}, + "group_work": {"gained_points": 0, "all_points": 0}, + "product_project": {"gained_points": 0, "all_points": 0}, + } - second_term_points = copy.deepcopy(first_term_points) + second_term_points = copy.deepcopy(first_term_points) - for weight_key, weight_value in weights.items(): - points = ( - first_term_points if weight_key.endswith("1") else second_term_points - ) - criterion = get_criterion_by_weight_key(weight_key) - try: - attribute_value = getattr(pgs, weight_key) - except AttributeError: - attribute_value = 0 - points[criterion]["gained_points"] += attribute_value / 4 * weight_value - points[criterion]["all_points"] += weight_value + for weight_key, weight_value in weights.items(): + points = first_term_points if weight_key.endswith("1") else second_term_points + criterion = get_criterion_by_weight_key(weight_key) + try: + attribute_value = getattr(project_grade_sheet, weight_key) + except AttributeError: + attribute_value = 0 + points[criterion]["gained_points"] += attribute_value / 4 * weight_value + points[criterion]["all_points"] += weight_value - points_1 = round(grade_in_percentage("FIRST_TERM", first_term_points) * 100, 1) - points_2 = round( - grade_in_percentage("SECOND_TERM", second_term_points) * 100, 1 - ) - terms.append((points_1, points_2)) - return terms + points_1 = round(grade_in_percentage("FIRST_TERM", first_term_points) * 100, 1) + points_2 = round(grade_in_percentage("SECOND_TERM", second_term_points) * 100, 1) + return points_1, points_2 -def attach_points_for_first_and_second_term_to_group_models(items: List[Group]) -> None: +def attach_points_for_first_and_second_term_to_group(group: Group) -> None: weights = load_weight_for_project_grade_sheet() - pgs = [] - for g in items: - if len(g.project_grade_sheet) == 0: - pgs.append(None) - else: - pgs.append(g.project_grade_sheet[0]) - calculated_points = calculate_points_for_both_terms(weights, pgs) + pgs = group.project_grade_sheet + if len(pgs) == 0: + pgs = None + else: + pgs = pgs[0] + points = calculate_points_for_both_terms(weights, pgs) + group.points_for_first_term = points[0] + group.points_for_second_term = points[1] - for group, points in zip(items, calculated_points): - group.points_for_first_term = points[0] - group.points_for_second_term = points[1] + +def get_term_grade(point: float) -> float: + if point >= 91.0: + return 5 + if point >= 81.0: + return 4.5 + if point >= 71.0: + return 4 + if point >= 61.0: + return 3.5 + if point >= 51.0: + return 3 + return 2 + + +def attach_grade_to_group_models(groups: List[Group]) -> None: + for group in groups: + if group.grade_for_first_term == 0: + group.grade_for_first_term = get_term_grade(group.points_for_first_term) + if group.grade_for_second_term == 0: + group.grade_for_second_term = get_term_grade(group.points_for_second_term) diff --git a/backend/app/project_supervisor/query/project_grade_sheet.py b/backend/app/project_supervisor/query/project_grade_sheet.py index 6d0d6f8..1b6151d 100644 --- a/backend/app/project_supervisor/query/project_grade_sheet.py +++ b/backend/app/project_supervisor/query/project_grade_sheet.py @@ -1,11 +1,14 @@ from flask import abort +from ...coordinator.utils import attach_points_for_first_and_second_term_to_group from ...dependencies import db from ...students.models import Group, ProjectGradeSheet from ..models import ProjectSupervisor -def update_project_grade_sheet(group_id: int, query: dict, data: dict) -> None: +def update_project_grade_sheet( + group_id: int, query: dict, data: dict +) -> ProjectGradeSheet: project_supervisor_id = query.get("id") project_supervisor = ProjectSupervisor.query.filter( ProjectSupervisor.id == project_supervisor_id @@ -28,4 +31,5 @@ def update_project_grade_sheet(group_id: int, query: dict, data: dict) -> None: abort(404, "Not found project grade sheet!") pgs_query.update(data) + attach_points_for_first_and_second_term_to_group(group) db.session.commit() diff --git a/backend/app/students/models.py b/backend/app/students/models.py index d72c71a..a228024 100644 --- a/backend/app/students/models.py +++ b/backend/app/students/models.py @@ -40,6 +40,8 @@ class Group(Base): year_group = db.relationship("YearGroup", backref="groups", lazy="joined") points_for_first_term = db.Column(db.Float, default=0, nullable=False) points_for_second_term = db.Column(db.Float, default=0, nullable=False) + grade_for_first_term = db.Column(db.Float, default=0, nullable=False) + grade_for_second_term = db.Column(db.Float, default=0, nullable=False) students = db.relationship( "Student", secondary=students_groups, back_populates="groups" ) diff --git a/backend/migrations/versions/e0e58661131a_.py b/backend/migrations/versions/5f2f440d05e2_.py similarity index 98% rename from backend/migrations/versions/e0e58661131a_.py rename to backend/migrations/versions/5f2f440d05e2_.py index 809bc41..bae3880 100644 --- a/backend/migrations/versions/e0e58661131a_.py +++ b/backend/migrations/versions/5f2f440d05e2_.py @@ -1,15 +1,15 @@ """empty message -Revision ID: e0e58661131a +Revision ID: 5f2f440d05e2 Revises: -Create Date: 2023-01-15 23:21:20.996214 +Create Date: 2023-01-15 23:52:36.927007 """ import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. -revision = "e0e58661131a" +revision = "5f2f440d05e2" down_revision = None branch_labels = None depends_on = None @@ -106,6 +106,8 @@ def upgrade(): sa.Column("year_group_id", sa.Integer(), nullable=True), sa.Column("points_for_first_term", sa.Float(), nullable=False), sa.Column("points_for_second_term", sa.Float(), nullable=False), + sa.Column("grade_for_first_term", sa.Float(), nullable=False), + sa.Column("grade_for_second_term", sa.Float(), nullable=False), sa.ForeignKeyConstraint( ["project_supervisor_id"], ["project_supervisors.id"],