Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[email protected] changes made #184

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions core/apis/assignments/principal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@
from core import db
from core.apis import decorators
from core.apis.responses import APIResponse
from core.models.assignments import Assignment
from core.models.assignments import Assignment, Teacher

from .schema import AssignmentSchema, AssignmentGradeSchema, TeacherSchema

from .schema import AssignmentSchema, AssignmentGradeSchema
principal_assignments_resources = Blueprint('principal_assignments_resources', __name__)


@principal_assignments_resources.route('/assignments', methods=['GET'], strict_slashes=False)
@decorators.authenticate_principal
def list_assignments(p):
"""Returns list of assignments"""
principals_assignments = Assignment.get_assignments_by_principal()
principals_assignments_dump = AssignmentSchema().dump(principals_assignments, many=True)
return APIResponse.respond(data=principals_assignments_dump)
submitted_or_graded_assignment = Assignment.get_submitted_or_graded_assignments(
) # this is a python obj that we want to store persistently inside a db.
principal_assignments_dump = AssignmentSchema().dump(
submitted_or_graded_assignment, many=True) # but before that we need to serialize it so that it could be sent over the wire.
return APIResponse.respond(data=principal_assignments_dump)


# GET /principal/teachers
@principal_assignments_resources.route("/teachers", methods=['GET'], strict_slashes=False)
@decorators.authenticate_principal
def get_teachers(p):
""" Returns a list of the Teachers. """
teachers = Teacher.list_teachers()
teachers_dump = TeacherSchema().dump(teachers, many=True)
return APIResponse.respond(data=teachers_dump)


@principal_assignments_resources.route('/assignments/grade', methods=['POST'], strict_slashes=False)
Expand Down
21 changes: 20 additions & 1 deletion core/apis/assignments/schema.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from marshmallow import Schema, EXCLUDE, fields, post_load
from marshmallow_sqlalchemy import SQLAlchemyAutoSchema, auto_field
from marshmallow_enum import EnumField
from core.models.assignments import Assignment, GradeEnum
from core.models.assignments import Assignment, GradeEnum, Teacher
from core.libs.helpers import GeneralObject


Expand Down Expand Up @@ -49,3 +49,22 @@ class Meta:
def initiate_class(self, data_dict, many, partial):
# pylint: disable=unused-argument,no-self-use
return GeneralObject(**data_dict)

class TeacherSchema(SQLAlchemyAutoSchema):
# this is the pragma | directive thing that we ve got to instruct marshmallow-sqlalchemy for config purpose.
class Meta:
# let em know what model to use to generate the auto schema.
model = Teacher
# exclude all them unknown pros and dont raise an error for that thing.
unknown = EXCLUDE

id = auto_field(allow_none=False, required=True) # being consistent with the table attrs.
user_id = auto_field()
# dont want to update those fields while deserialzing.
created_at = auto_field(dump_only=True)
updated_at = auto_field(dump_only=True)

""" this method is ivked when we got to deserialize. many repr that we're going to ve multiple dicts | dicts[]. partial is used to flag the checkpoint that we're going to create the obj from scratch or only some of them. dump_only kicks right in here. """
@post_load
def initiate_class(self, data_dict, many, partial):
return GeneralObject(**data_dict)
3 changes: 3 additions & 0 deletions core/apis/assignments/student.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from core.apis import decorators
from core.apis.responses import APIResponse
from core.models.assignments import Assignment
from core.libs import assertions

from .schema import AssignmentSchema, AssignmentSubmitSchema
student_assignments_resources = Blueprint('student_assignments_resources', __name__)
Expand All @@ -25,6 +26,8 @@ def upsert_assignment(p, incoming_payload):
assignment = AssignmentSchema().load(incoming_payload)
assignment.student_id = p.student_id

assertions.assert_valid(assignment.content != None, "Assignment with null content cannot be submitted.")

upserted_assignment = Assignment.upsert(assignment)
db.session.commit()
upserted_assignment_dump = AssignmentSchema().dump(upserted_assignment)
Expand Down
27 changes: 24 additions & 3 deletions core/apis/assignments/teacher.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
from flask import Blueprint
from core.apis import decorators
from core import db
from core.apis.responses import APIResponse
from core.models.assignments import Assignment
from .schema import AssignmentSchema, AssignmentGradeSchema


from .schema import AssignmentSchema
teacher_assignments_resources = Blueprint('teacher_assignments_resources', __name__)


@teacher_assignments_resources.route('/assignments', methods=['GET'], strict_slashes=False)
@decorators.authenticate_principal
def list_assignments(p):
"""Returns list of assignments"""
teachers_assignments = Assignment.get_assignments_by_teacher()
teachers_assignments_dump = AssignmentSchema().dump(teachers_assignments, many=True)
teacher_id = p.teacher_id
teachers_assignments = Assignment.get_assignments_by_teacher(teacher_id)
teachers_assignments_dump = AssignmentSchema().dump(
teachers_assignments, many=True)
return APIResponse.respond(data=teachers_assignments_dump)

# POST /teacher/assignments/grade
@teacher_assignments_resources.route('/assignments/grade', methods=['POST'], strict_slashes=False)
@decorators.accept_payload
@decorators.authenticate_principal
def grade_assignment(p, incoming_payload):
"""Grade an assignment"""
grade_assignment_payload = AssignmentGradeSchema().load(incoming_payload)
graded_assignment = Assignment.mark_grade(
_id=grade_assignment_payload.id,
grade=grade_assignment_payload.grade,
auth_principal=p
)

db.session.commit()
graded_assignment_dump = AssignmentSchema().dump(graded_assignment)
return APIResponse.respond(data=graded_assignment_dump)
29 changes: 29 additions & 0 deletions core/models/assignments.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ def submit(cls, _id, teacher_id, auth_principal: AuthPrincipal):
assertions.assert_found(assignment, 'No assignment with this id was found')
assertions.assert_valid(assignment.student_id == auth_principal.student_id, 'This assignment belongs to some other student')
assertions.assert_valid(assignment.content is not None, 'assignment with empty content cannot be submitted')
assertions.assert_valid(assignment.state == AssignmentStateEnum.DRAFT,"only a draft assignment can be submitted")

assignment.teacher_id = teacher_id
assignment.state = AssignmentStateEnum.SUBMITTED
db.session.flush()

return assignment
Expand All @@ -78,6 +80,10 @@ def mark_grade(cls, _id, grade, auth_principal: AuthPrincipal):
assertions.assert_found(assignment, 'No assignment with this id was found')
assertions.assert_valid(grade is not None, 'assignment with empty grade cannot be graded')

assertions.assert_valid(assignment.teacher_id == auth_principal.teacher_id,f"Assignment with id: {assignment.id} is not submitted to Teacher with teacher_id: {auth_principal.teacher_id}")
# teacher cant regrade a assignment.
assertions.assert_valid(assignment.state != AssignmentStateEnum.GRADED, f"Teacher cant regrade an assignment.")

assignment.grade = grade
assignment.state = AssignmentStateEnum.GRADED
db.session.flush()
Expand All @@ -95,3 +101,26 @@ def get_assignments_by_teacher(cls):
@classmethod
def get_assignments_by_principal(cls):
return cls.filter(cls.state != AssignmentStateEnum.DRAFT).all()

@classmethod
def get_submitted_or_graded_assignments(cls):
return cls.filter(cls.state in [AssignmentStateEnum.SUBMITTED, AssignmentStateEnum.GRADED]).all()

@classmethod
def regrade(cls, _id, grade):
assignment = Assignment.get_by_id(_id)
assertions.assert_found(assignment, f"No assignment with id: {_id} found.")
assertions.assert_valid(
grade is not None, 'assignment with empty grade cannot be graded')
# principal can grade submitted assignments | regrade graded assignments only.
assertions.assert_valid(assignment.state != AssignmentStateEnum.DRAFT, f"Principal cannot grade assignment in {assignment.state} state.")

assignment.grade = grade

# dont ve to change the state if already graded.
if(assignment.state == AssignmentStateEnum.SUBMITTED):
assignment.state = AssignmentStateEnum.GRADED

db.session.flush()

return assignment
6 changes: 6 additions & 0 deletions core/models/teachers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ class Teacher(db.Model):

def __repr__(self):
return '<Teacher %r>' % self.id

@classmethod
def list_teachers(cls):
""" Returns a list of Teachers. """
list_of_teachers = db.session.execute(db.select(cls)).scalars()
return list_of_teachers