Add artifact updated_at and created_at values to LOR LEs

This PS added artifact_updated_at and artifact_created_at dates
to learning_outcome_result_created and
learning_outcome_result_updated live event.  These values will
be used to determine if the live event was received out of order
meaning it is an old event so that the audit will not process
the event.

closes OUT-6499
flag=none

Test plan:
- Tests are sufficient and Jenkins passes

Change-Id: I62580da48b5ae6e66412af9f559d6ad6094f653c
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/351490
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Angela Gomba <angela.gomba@instructure.com>
QA-Review: Angela Gomba <angela.gomba@instructure.com>
Product-Review: Dave Wenzlick <david.wenzlick@instructure.com>
This commit is contained in:
Chrystal Langston 2024-06-28 16:47:03 -04:00 committed by Dave Wenzlick
parent 087642b1a6
commit f1ccc50966
5 changed files with 153 additions and 18 deletions

View File

@ -21,7 +21,9 @@
"score": "The student's score.",
"user_uuid": "The unique identifier for the user that the outcome was assessed.",
"artifact_id": "The id of the artifact that contains the outcome assessment. Value will be an string representation of an integer or nil.",
"artifact_type": "The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, or LiveAssessments::Submission.",
"artifact_type": "The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, LiveAssessments::Submission or nil.",
"artifact_updated_at": "The date when the artifact was last updated or nil.",
"artifact_created_at": "The date when the artifact was created or nil.",
"associated_asset_id": "The id of the asset that the outcome is aligned to. Value will be an string representation of an integer or nil.",
"associated_asset_type": "The type of the asset that the outcome is aligned to. Value will be one of the following: AssessmentQuestion, Assignment, Quizzes::Quiz, LiveAssessments::Assessment or nil."
},
@ -58,6 +60,8 @@
"user_uuid": "elXwFPr6uKGaiVxchQSsqV6YZy5HBtlq8O2vqMXM",
"artifact_id": "22",
"artifact_type": "RubricAssessment",
"artifact_updated_at": "2019-08-09T21:33:05Z",
"artifact_created_at": "2019-08-09T21:33:05Z",
"associated_asset_id": "56",
"associated_asset_type": "Assignment"
}

View File

@ -22,7 +22,9 @@
"updated_at": "Time the learning outcome result was updated at.",
"user_uuid": "The uuid of the user that the outcome was assessed.",
"artifact_id": "The id of the artifact that contains the outcome assessment. Value will be an string representation of an integer or nil.",
"artifact_type": "The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, or LiveAssessments::Submission.",
"artifact_type": "The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, LiveAssessments::Submission or nil.",
"artifact_updated_at": "The date when the artifact was last updated or nil.",
"artifact_created_at": "The date when the artifact was created or nil.",
"associated_asset_id": "The id of the asset that the outcome is aligned to. Value will be an string representation of an integer or nil.",
"associated_asset_type": "The type of the asset that the outcome is aligned to. Value will be one of the following: AssessmentQuestion, Assignment, Quizzes::Quiz, LiveAssessments::Assessment or nil."
},
@ -60,6 +62,8 @@
"user_uuid": "elXwFPr6uKGaiVxchQSsqV6YZy5HBtlq8O2vqMXM",
"artifact_id": "22",
"artifact_type": "RubricAssessment",
"artifact_updated_at": "2019-08-09T21:33:05Z",
"artifact_created_at": "2019-08-09T21:33:05Z",
"associated_asset_id": "56",
"associated_asset_type": "Assignment"
}

View File

@ -376,6 +376,8 @@ Learning
"user_uuid": "elXwFPr6uKGaiVxchQSsqV6YZy5HBtlq8O2vqMXM",
"artifact_id": "22",
"artifact_type": "RubricAssessment",
"artifact_updated_at": "2019-08-09T21:33:05Z",
"artifact_created_at": "2019-08-09T21:33:05Z",
"associated_asset_id": "56",
"associated_asset_type": "Assignment"
}
@ -407,7 +409,9 @@ Learning
| **score** | The student's score. |
| **user_uuid** | The unique identifier for the user that the outcome was assessed. |
| **artifact_id** | The id of the artifact that contains the outcome assessment. Value will be an string representation of an integer or nil. |
| **artifact_type** | The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, or LiveAssessments::Submission. |
| **artifact_type** | The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, LiveAssessments::Submission or nil. |
| **artifact_updated_at** | The date when the artifact was last updated or nil. |
| **artifact_created_at** | The date when the artifact was created or nil. |
| **associated_asset_id** | The id of the asset that the outcome is aligned to. Value will be an string representation of an integer or nil. |
| **associated_asset_type** | The type of the asset that the outcome is aligned to. Value will be one of the following: AssessmentQuestion, Assignment, Quizzes::Quiz, LiveAssessments::Assessment or nil. |
@ -457,6 +461,8 @@ Learning
"user_uuid": "elXwFPr6uKGaiVxchQSsqV6YZy5HBtlq8O2vqMXM",
"artifact_id": "22",
"artifact_type": "RubricAssessment",
"artifact_updated_at": "2019-08-09T21:33:05Z",
"artifact_created_at": "2019-08-09T21:33:05Z",
"associated_asset_id": "56",
"associated_asset_type": "Assignment"
}
@ -489,7 +495,9 @@ Learning
| **updated_at** | Time the learning outcome result was updated at. |
| **user_uuid** | The uuid of the user that the outcome was assessed. |
| **artifact_id** | The id of the artifact that contains the outcome assessment. Value will be an string representation of an integer or nil. |
| **artifact_type** | The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, or LiveAssessments::Submission. |
| **artifact_type** | The type of artifact that contains the outcome assessment. Value will be one of the following: RubricAssessment, Submission, Quizzes::QuizSubmission, LiveAssessments::Submission or nil. |
| **artifact_updated_at** | The date when the artifact was last updated or nil. |
| **artifact_created_at** | The date when the artifact was created or nil. |
| **associated_asset_id** | The id of the asset that the outcome is aligned to. Value will be an string representation of an integer or nil. |
| **associated_asset_type** | The type of the asset that the outcome is aligned to. Value will be one of the following: AssessmentQuestion, Assignment, Quizzes::Quiz, LiveAssessments::Assessment or nil. |

View File

@ -820,6 +820,24 @@ module Canvas::LiveEvents
end
end
def self.learning_outcome_result_artifact_updated_and_created_at_data(result)
# Like associated_asset, learning outcome result artifact can be nil as there is nothing on a model
# that forces it to be present. This seems like an oversight as by definition an artifact is the
# the submission for the assessable content that contains the grade/score. i.e. RubricAssessment,
# Submission, Quizzes::QuizSubmission, or LiveAssessments::Submission. May be there is some legacy
# knowledge that has been lost as to why to allow this to be nullable? Until then, we will need to
# treat this as a possiblity.
# Since artifact can be nil, which inturn means that result.artifact_id and result.artifact_type would
# be nil, we need to check if artifact is nil and if so, do not include the artifact's updated_at and
# created_at attributes.
return {} if result.artifact.nil?
{
artifact_updated_at: result.artifact.updated_at,
artifact_created_at: result.artifact.created_at,
}
end
def self.get_learning_outcome_result_data(result)
{
id: result.id,
@ -840,10 +858,10 @@ module Canvas::LiveEvents
percent: result.percent,
workflow_state: result.workflow_state,
user_uuid: result.user_uuid,
artifact_id: result.artifact_id,
artifact_type: result.artifact_type,
associated_asset_id: result.associated_asset_id,
associated_asset_type: result.associated_asset_type
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id,
artifact_type: result.artifact_type
}
end
@ -855,7 +873,7 @@ module Canvas::LiveEvents
# Given this, if the learning outcome results workflow state is deleted, do not worry about updating
# the associated asset information as the rubric association no longer exists.
rubric_assessment_learning_outcome_result_associated_asset(result) unless result.workflow_state == "deleted"
post_event_stringified("learning_outcome_result_updated", get_learning_outcome_result_data(result).merge(updated_at: result.updated_at))
post_event_stringified("learning_outcome_result_updated", get_learning_outcome_result_data(result).merge(updated_at: result.updated_at).merge(learning_outcome_result_artifact_updated_and_created_at_data(result)))
end
def self.learning_outcome_result_created(result)
@ -866,7 +884,7 @@ module Canvas::LiveEvents
# Given this, if the learning outcome results workflow state is deleted, do not worry about updating
# the associated asset information as the rubric association no longer exists.
rubric_assessment_learning_outcome_result_associated_asset(result) unless result.workflow_state == "deleted"
post_event_stringified("learning_outcome_result_created", get_learning_outcome_result_data(result))
post_event_stringified("learning_outcome_result_created", get_learning_outcome_result_data(result).merge(learning_outcome_result_artifact_updated_and_created_at_data(result)))
end
# Since outcome service canvas learning_outcome global id record won't match outcomes service shard

View File

@ -1884,7 +1884,26 @@ describe Canvas::LiveEvents do
end
end
context "#rubric_assessment_learning_outcome_result_associated_asset" do
describe "#learning_outcome_result_artifact_updated_and_created_at_data" do
it "returns the updated_at and created_at data for the artifact" do
expect(
Canvas::LiveEvents.learning_outcome_result_artifact_updated_and_created_at_data(result)
).to eq(
{
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}
)
end
it "returns empty set if the artifact is nil" do
result.update!(artifact: nil)
result.reload
expect(Canvas::LiveEvents.learning_outcome_result_artifact_updated_and_created_at_data(result)).to eq({})
end
end
describe "#rubric_assessment_learning_outcome_result_associated_asset" do
it "updates associated_asset info to the assignment if the artifact is a RubricAssessment" do
assignment_model
course_with_student
@ -1916,13 +1935,81 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_created(result)
end
end
context "artifact is not associated with learning outcome result" do
before do
result.update!(artifact: nil)
result.reload
end
it "artifact_id and artifact_type are nil in created live event" do
expect_event("learning_outcome_result_created", {
id: result.id.to_s,
learning_outcome_id: result.learning_outcome_id.to_s,
learning_outcome_context_uuid: result.learning_outcome.context&.uuid,
result_context_id: result.context_id.to_s,
result_context_type: result.context_type,
result_context_uuid: result&.context&.uuid,
mastery: result.mastery,
score: result.score,
created_at: result.created_at,
attempt: result.attempt,
possible: result.possible,
original_score: result.original_score,
original_possible: result.original_possible,
original_mastery: result.original_mastery,
assessed_at: result.assessed_at,
percent: result.percent,
workflow_state: result.workflow_state,
user_uuid: result.user_uuid,
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: nil,
artifact_type: nil
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_created(result)
end
it "artifact_id and artifact_type are nil in updated live event" do
expect_event("learning_outcome_result_updated", {
id: result.id.to_s,
learning_outcome_id: result.learning_outcome_id.to_s,
learning_outcome_context_uuid: result.learning_outcome.context&.uuid,
result_context_id: result.context_id.to_s,
result_context_type: result.context_type,
result_context_uuid: result&.context&.uuid,
mastery: result.mastery,
score: result.score,
created_at: result.created_at,
updated_at: result.updated_at,
attempt: result.attempt,
possible: result.possible,
original_score: result.original_score,
original_possible: result.original_possible,
original_mastery: result.original_mastery,
assessed_at: result.assessed_at,
percent: result.percent,
workflow_state: result.workflow_state,
user_uuid: result.user_uuid,
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: nil,
artifact_type: nil
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_updated(result)
end
end
context "created" do
it "includes result in created live event" do
expect_event("learning_outcome_result_created", {
@ -1947,7 +2034,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_created(result)
@ -1977,7 +2066,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_created(result)
@ -2012,7 +2103,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_created(result)
@ -2046,7 +2139,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_updated(result)
@ -2078,7 +2173,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_updated(result)
@ -2109,7 +2206,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_updated(result)
@ -2145,7 +2244,9 @@ describe Canvas::LiveEvents do
associated_asset_id: result.associated_asset_id.to_s,
associated_asset_type: result.associated_asset_type,
artifact_id: result.artifact_id.to_s,
artifact_type: result.artifact_type
artifact_type: result.artifact_type,
artifact_created_at: result.artifact.created_at,
artifact_updated_at: result.artifact.updated_at
}.compact!).once
Canvas::LiveEvents.learning_outcome_result_updated(result)