From f205f7874c2bb74fb1dac61a1bb2dec994975e5d Mon Sep 17 00:00:00 2001 From: Brian Mesick Date: Tue, 19 Nov 2024 13:01:06 -0500 Subject: [PATCH] docs: Add PII annotations to models Per OEP-30 these annotations should live with the models. This is just moving the existing edx-platform overrides to the correct location. --- openassessment/assessment/models/base.py | 11 +++++++++++ openassessment/assessment/models/peer.py | 6 ++++++ openassessment/assessment/models/staff.py | 3 +++ openassessment/assessment/models/student_training.py | 4 ++++ openassessment/assessment/models/training.py | 2 ++ openassessment/staffgrader/models/submission_lock.py | 2 ++ openassessment/workflow/models.py | 7 +++++++ 7 files changed, 35 insertions(+) diff --git a/openassessment/assessment/models/base.py b/openassessment/assessment/models/base.py index 05c9f9b62c..ebcc85079c 100644 --- a/openassessment/assessment/models/base.py +++ b/openassessment/assessment/models/base.py @@ -70,6 +70,8 @@ class Rubric(models.Model): once created, they're never updated. When the problem changes, we end up creating a new Rubric instead. This makes it easy to cache and do hash-based lookups. + + .. no_pii: """ # SHA1 hash, including prompts and explanations content_hash = models.CharField(max_length=40, unique=True, db_index=True) @@ -160,6 +162,8 @@ class Criterion(models.Model): and clarity. Each of those would be separate criteria. All Rubrics have at least one Criterion. + + .. no_pii: """ rubric = models.ForeignKey(Rubric, related_name="criteria", on_delete=models.CASCADE) @@ -199,6 +203,8 @@ class CriterionOption(models.Model): Note that this is the representation of the choice itself, *not* a representation of a particular assessor's choice for a particular Assessment. That state is stored in :class:`AssessmentPart`. + + .. no_pii: """ # All Criteria must have at least one CriterionOption. criterion = models.ForeignKey(Criterion, related_name="options", on_delete=models.CASCADE) @@ -419,6 +425,8 @@ class Assessment(models.Model): an assessment of some submission. It is composed of :class:`AssessmentPart` objects that map to each :class:`Criterion` in the :class:`Rubric` we're assessing against. + + .. no_pii: """ MAX_FEEDBACK_SIZE = 1024 * 100 @@ -689,6 +697,8 @@ class AssessmentPart(models.Model): It's implemented as a foreign key to the `CriterionOption` that was chosen by this assessor for this `Criterion`. So basically, think of this class as :class:`CriterionOption` + student state. + + .. no_pii: """ MAX_FEEDBACK_SIZE = 1024 * 100 @@ -911,6 +921,7 @@ class SharedFileUpload(TimeStampedModel): """ Define a single file uploaded by a student when attached to a team. + .. no_pii: """ team_id = models.CharField(max_length=255, db_index=True) course_id = models.CharField(max_length=255, db_index=True) diff --git a/openassessment/assessment/models/peer.py b/openassessment/assessment/models/peer.py index 8fa13006b6..a9e1b8bb47 100644 --- a/openassessment/assessment/models/peer.py +++ b/openassessment/assessment/models/peer.py @@ -34,6 +34,8 @@ class AssessmentFeedbackOption(models.Model): Over time, we may decide to add, delete, or reword assessment feedback options. To preserve data integrity, we will always get-or-create `AssessmentFeedbackOption`s based on the option text. + + .. no_pii: """ text = models.CharField(max_length=255, unique=True) @@ -53,6 +55,8 @@ class AssessmentFeedback(models.Model): ("Please provide any thoughts or comments on the feedback you received from your peers") as well as zero or more feedback options ("Please select the statements below that reflect what you think of this peer grading experience") + + .. no_pii: """ MAXSIZE = 1024 * 100 # 100KB @@ -107,6 +111,7 @@ class PeerWorkflow(models.Model): The student item is the author of the submission. Peer Workflow Items are created for each assessment made by this student. + .. no_pii: """ # Amount of time before a lease on a submission expires TIME_LIMIT = timedelta(hours=getattr(settings, "ORA_PEER_LEASE_EXPIRATION_HOURS", 8)) @@ -514,6 +519,7 @@ class PeerWorkflowItem(models.Model): associated workflow represents the scorer of the given submission, and the assessment represents the completed assessment for this work item. + .. no_pii: """ scorer = models.ForeignKey(PeerWorkflow, related_name='graded', on_delete=models.CASCADE) author = models.ForeignKey(PeerWorkflow, related_name='graded_by', on_delete=models.CASCADE) diff --git a/openassessment/assessment/models/staff.py b/openassessment/assessment/models/staff.py index 53ac1a2827..016464cd72 100644 --- a/openassessment/assessment/models/staff.py +++ b/openassessment/assessment/models/staff.py @@ -27,6 +27,7 @@ class StaffWorkflow(models.Model): 3) Does this staff member already have a submission open for assessment? 4) Close open assessments when completed. + .. no_pii: """ # Amount of time before a lease on a submission expires TIME_LIMIT = timedelta(hours=getattr(settings, "ORA_STAFF_LEASE_EXPIRATION_HOURS", 8)) @@ -214,6 +215,8 @@ def close_active_assessment(self, assessment, scorer_id): class TeamStaffWorkflow(StaffWorkflow): """ Extends the StafWorkflow to be used for team based assessments. + + .. no_pii: """ team_submission_uuid = models.CharField(max_length=128, unique=True, null=False) diff --git a/openassessment/assessment/models/student_training.py b/openassessment/assessment/models/student_training.py index 41b22f38f4..796f365072 100644 --- a/openassessment/assessment/models/student_training.py +++ b/openassessment/assessment/models/student_training.py @@ -13,6 +13,8 @@ class StudentTrainingWorkflow(models.Model): """ Tracks a student's progress through the student training assessment step. + + .. no_pii: """ # The submission UUID of the student being trained submission_uuid = models.CharField(max_length=128, db_index=True, unique=True) @@ -183,6 +185,8 @@ class StudentTrainingWorkflowItem(models.Model): then the student proceeds to the next example; if there are no examples left, the student has successfully completed training. + + .. no_pii: """ workflow = models.ForeignKey(StudentTrainingWorkflow, related_name="items", on_delete=models.CASCADE) order_num = models.PositiveIntegerField() diff --git a/openassessment/assessment/models/training.py b/openassessment/assessment/models/training.py index 01684a69b6..126aabd6ca 100644 --- a/openassessment/assessment/models/training.py +++ b/openassessment/assessment/models/training.py @@ -15,6 +15,8 @@ class TrainingExample(models.Model): """ An example assessment used to train students (before peer assessment) or AI. + + .. no_pii: """ # The answer (JSON-serialized) raw_answer = models.TextField(blank=True) diff --git a/openassessment/staffgrader/models/submission_lock.py b/openassessment/staffgrader/models/submission_lock.py index f14af830ba..d2d5b17d81 100644 --- a/openassessment/staffgrader/models/submission_lock.py +++ b/openassessment/staffgrader/models/submission_lock.py @@ -12,6 +12,8 @@ class SubmissionGradingLock(models.Model): """ Internal model for locking a submission for exclusive grading + + .. no_pii: """ TIMEOUT = StaffWorkflow.TIME_LIMIT diff --git a/openassessment/workflow/models.py b/openassessment/workflow/models.py index 908b5bad49..7037e75ecf 100644 --- a/openassessment/workflow/models.py +++ b/openassessment/workflow/models.py @@ -61,6 +61,8 @@ class AssessmentWorkflow(TimeStampedModel, StatusModel): submissions you have to assess = 5"). The "status" field on this model is an after the fact recording of the last known state of that information so we can search easily. + + .. no_pii: """ STAFF_STEP_NAME = 'staff' @@ -701,6 +703,8 @@ def identifying_uuid(self): class TeamAssessmentWorkflow(AssessmentWorkflow): """ Extends AssessmentWorkflow to support team based assessments. + + .. no_pii: """ # Only staff assessments are supported for teams TEAM_STAFF_STEP_NAME = 'teams' @@ -855,6 +859,7 @@ class AssessmentWorkflowStep(models.Model): sync until someone views this problem again (which will trigger a workflow update to occur). + .. no_pii: """ workflow = models.ForeignKey(AssessmentWorkflow, related_name="steps", on_delete=models.CASCADE) name = models.CharField(max_length=20) @@ -1029,6 +1034,8 @@ class AssessmentWorkflowCancellation(models.Model): It is created when a staff member requests removal of a submission from the peer grading pool. + + .. no_pii: """ workflow = models.ForeignKey(AssessmentWorkflow, related_name='cancellations', on_delete=models.CASCADE) comments = models.TextField(max_length=10000)