diff --git a/lms/models/__init__.py b/lms/models/__init__.py index 80e10d59ae..71a375248c 100644 --- a/lms/models/__init__.py +++ b/lms/models/__init__.py @@ -2,7 +2,10 @@ from lms.models.application_instance import ApplicationInstance, ApplicationSettings from lms.models.assignment import Assignment, AutoGradingConfig from lms.models.assignment_grouping import AssignmentGrouping -from lms.models.assignment_membership import AssignmentMembership +from lms.models.assignment_membership import ( + AssignmentMembership, + LMSUserAssignmentMembership, +) from lms.models.course_groups_exported_from_h import CourseGroupsExportedFromH from lms.models.dashboard_admin import DashboardAdmin from lms.models.event import Event, EventData, EventType, EventUser diff --git a/lms/models/assignment_membership.py b/lms/models/assignment_membership.py index e398fab54d..88b2726769 100644 --- a/lms/models/assignment_membership.py +++ b/lms/models/assignment_membership.py @@ -1,4 +1,5 @@ -import sqlalchemy as sa +from sqlalchemy import ForeignKey, UniqueConstraint +from sqlalchemy.orm import Mapped, mapped_column, relationship from lms.db import Base from lms.models._mixins import CreatedUpdatedMixin @@ -9,29 +10,52 @@ class AssignmentMembership(CreatedUpdatedMixin, Base): __tablename__ = "assignment_membership" - assignment_id = sa.Column( - sa.Integer(), - sa.ForeignKey("assignment.id", ondelete="cascade"), - primary_key=True, - index=True, + assignment_id: Mapped[int] = mapped_column( + ForeignKey("assignment.id", ondelete="cascade"), primary_key=True, index=True ) - assignment = sa.orm.relationship("Assignment", foreign_keys=[assignment_id]) + assignment = relationship("Assignment", foreign_keys=[assignment_id]) """The assignment the user is a member of.""" - user_id = sa.Column( - sa.Integer(), - sa.ForeignKey("user.id", ondelete="cascade"), - primary_key=True, - index=True, + user_id: Mapped[int] = mapped_column( + ForeignKey("user.id", ondelete="cascade"), primary_key=True, index=True ) - user = sa.orm.relationship("User", foreign_keys=[user_id]) + user = relationship("User", foreign_keys=[user_id]) """The user who is a member.""" - lti_role_id = sa.Column( - sa.Integer(), - sa.ForeignKey("lti_role.id", ondelete="cascade"), - primary_key=True, + lti_role_id: Mapped[int] = mapped_column( + ForeignKey("lti_role.id", ondelete="cascade"), primary_key=True, index=True + ) + lti_role = relationship("LTIRole", foreign_keys=[lti_role_id]) + """What role the user plays in the assignment.""" + + +class LMSUserAssignmentMembership(CreatedUpdatedMixin, Base): + """Record of LMSUser that have launched one particular assignment. + + One row for each assignment, user and role. + """ + + __tablename__ = "lms_user_assignment_membership" + __table_args__ = (UniqueConstraint("assignment_id", "lms_user_id", "lti_role_id"),) + + id: Mapped[int] = mapped_column(autoincrement=True, primary_key=True) + + assignment_id: Mapped[int] = mapped_column( + ForeignKey("assignment.id", ondelete="cascade"), index=True + ) + assignment = relationship("Assignment", foreign_keys=[assignment_id]) + + lms_user_id: Mapped[int] = mapped_column( + ForeignKey("lms_user.id", ondelete="cascade"), index=True + ) + lms_user = relationship("LMSUser", foreign_keys=[lms_user_id]) + + lti_role_id: Mapped[int] = mapped_column( + ForeignKey("lti_role.id", ondelete="cascade"), index=True, ) - lti_role = sa.orm.relationship("LTIRole", foreign_keys=[lti_role_id]) + lti_role = relationship("LTIRole", foreign_keys=[lti_role_id]) """What role the user plays in the assignment.""" + + lti_v11_lis_result_sourcedid: Mapped[str | None] = mapped_column() + """LTI's lis_result_sourcedid, the relevant ID of one user in one assigment for the LTI1.1 grading API.""" diff --git a/tests/factories/__init__.py b/tests/factories/__init__.py index 1efdafdd31..fd2604e452 100644 --- a/tests/factories/__init__.py +++ b/tests/factories/__init__.py @@ -6,7 +6,10 @@ from tests.factories.application_instance import ApplicationInstance from tests.factories.assignment import Assignment from tests.factories.assignment_grouping import AssignmentGrouping -from tests.factories.assignment_membership import AssignmentMembership +from tests.factories.assignment_membership import ( + AssignmentMembership, + LMSUserAssignmentMembership, +) from tests.factories.attributes import ( ACCESS_TOKEN, H_DISPLAY_NAME, diff --git a/tests/factories/assignment_membership.py b/tests/factories/assignment_membership.py index 2e3c086033..cf6711cd4e 100644 --- a/tests/factories/assignment_membership.py +++ b/tests/factories/assignment_membership.py @@ -6,3 +6,7 @@ AssignmentMembership = make_factory( models.AssignmentMembership, FACTORY_CLASS=SQLAlchemyModelFactory ) + +LMSUserAssignmentMembership = make_factory( + models.LMSUserAssignmentMembership, FACTORY_CLASS=SQLAlchemyModelFactory +)