add edited_at to submission_comments
closes GRADE-303 Test Plan: 1. Verify the migration succeeds, and verify you can also roll the migration back successfully. The rest of the steps will assume the migration has been run. 2. Create a course with an assignment. Submit to that assignment as a student, and comment on the submission as the student. 3. Make an API call to get the submissions and their comments for the assignment. GET api/v1/courses/:course_id/assignments/:id/submissions? include[]=submission_comments Verify the submission comments that are returned have an 'edited_at' key on them. The value of 'edited_at' should be nil for all comments. 4. Enter a rails console and update the 'comment' attribute on the submission comment. assignment = Assignment.find(<your-assignment-id>) student = User.find(<your-student-id>) submission = assignment.submissions.find_by(user_id: student) comment = submission.submission_comments.first comment.update!(comment: "i am updating the text on the comment!") 5. Make an API call to get the submissions and their comments for the assignment. GET api/v1/courses/:course_id/assignments/:id/submissions? include[]=submission_comments Verify the value of the 'edited_at' attribute for the comment you adjusted in step 4 is a timestamp. Change-Id: I4c91fdfd7a9cef194f08a2d086601fb827a50095 Reviewed-on: https://gerrit.instructure.com/127476 Tested-by: Jenkins Reviewed-by: Derek Bender <djbender@instructure.com> Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Keith T. Garner <kgarner@instructure.com> Reviewed-by: Rob Orton <rob@instructure.com>
This commit is contained in:
parent
81d775bd25
commit
e1d4b3ee4d
|
@ -78,6 +78,10 @@ require 'action_controller_test_process'
|
|||
# "example": "2012-01-01T01:00:00Z",
|
||||
# "type": "datetime"
|
||||
# },
|
||||
# "edited_at" : {
|
||||
# "example": "2012-01-02T01:00:00Z",
|
||||
# "type": "datetime"
|
||||
# },
|
||||
# "media_comment": {
|
||||
# "$ref": "MediaComment"
|
||||
# }
|
||||
|
|
|
@ -31,6 +31,7 @@ class SubmissionComment < ActiveRecord::Base
|
|||
validates_length_of :comment, :minimum => 1, :allow_nil => true, :allow_blank => true
|
||||
|
||||
before_save :infer_details
|
||||
before_save :set_edited_at
|
||||
after_save :update_participation
|
||||
after_save :check_for_media_object
|
||||
after_update :publish_other_comments_in_this_group
|
||||
|
@ -288,4 +289,10 @@ class SubmissionComment < ActiveRecord::Base
|
|||
def skip_group_callbacks?
|
||||
!!@skip_group_callbacks
|
||||
end
|
||||
|
||||
def set_edited_at
|
||||
if comment_changed? && comment_was.present?
|
||||
self.edited_at = Time.zone.now
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# Copyright (C) 2017 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class AddEditedAtToSubmissionComments < ActiveRecord::Migration[5.0]
|
||||
tag :predeploy
|
||||
|
||||
def change
|
||||
add_column :submission_comments, :edited_at, :datetime
|
||||
end
|
||||
end
|
|
@ -21,7 +21,7 @@ module Api::V1::SubmissionComment
|
|||
def submission_comment_json(submission_comment, user)
|
||||
sc_hash = submission_comment.as_json(
|
||||
:include_root => false,
|
||||
:only => %w(id author_id author_name created_at comment)
|
||||
:only => %w(id author_id author_name created_at edited_at comment)
|
||||
)
|
||||
|
||||
if submission_comment.media_comment?
|
||||
|
@ -52,6 +52,4 @@ module Api::V1::SubmissionComment
|
|||
def submission_comments_json(submission_comments, user)
|
||||
submission_comments.map{ |submission_comment| submission_comment_json(submission_comment, user) }
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -228,22 +228,30 @@ describe PeerReviewsApiController, type: :request do
|
|||
end
|
||||
|
||||
def assessment_with_comments(comment)
|
||||
{"assessor_id"=>@student2.id,
|
||||
"asset_id"=>@submission.id,
|
||||
"asset_type"=>"Submission",
|
||||
"id"=>@assessment_request.id,
|
||||
"submission_comments" => [{"author_id"=>@student2.id,
|
||||
"author_name"=>@student2.name,
|
||||
"comment"=>comment.comment,
|
||||
"created_at"=>comment.created_at.as_json,
|
||||
"id"=>comment.id,
|
||||
"author"=>{"id"=>@student2.id,
|
||||
"display_name"=>@student2.name,
|
||||
"avatar_image_url"=>"http://www.example.com/images/messages/avatar-50.png",
|
||||
"html_url"=>"http://www.example.com/courses/#{@course.id}/users/#{@student2.id}"}}],
|
||||
"user_id"=>@student1.id,
|
||||
"workflow_state"=>@assessment_request.workflow_state}
|
||||
|
||||
{
|
||||
"assessor_id" => @student2.id,
|
||||
"asset_id" => @submission.id,
|
||||
"asset_type" => "Submission",
|
||||
"id" => @assessment_request.id,
|
||||
"submission_comments" => [
|
||||
{
|
||||
"author_id" => @student2.id,
|
||||
"author_name" => @student2.name,
|
||||
"comment" => comment.comment,
|
||||
"created_at" => comment.created_at.as_json,
|
||||
"edited_at" => nil,
|
||||
"id" => comment.id,
|
||||
"author" => {
|
||||
"id" => @student2.id,
|
||||
"display_name" => @student2.name,
|
||||
"avatar_image_url" => "http://www.example.com/images/messages/avatar-50.png",
|
||||
"html_url" => "http://www.example.com/courses/#{@course.id}/users/#{@student2.id}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"user_id" => @student1.id,
|
||||
"workflow_state" => @assessment_request.workflow_state
|
||||
}
|
||||
end
|
||||
|
||||
context 'with admin_context' do
|
||||
|
@ -393,18 +401,27 @@ describe PeerReviewsApiController, type: :request do
|
|||
@user = @student1
|
||||
json = api_call(:get, @resource_path, @resource_params, { :include => %w(submission_comments) })
|
||||
expect(json.count).to eq(1)
|
||||
expect(json[0]).to eq({"asset_id"=>@submission.id,
|
||||
"asset_type"=>"Submission",
|
||||
"id"=>@assessment_request.id,
|
||||
"submission_comments" => [{"author_id"=>nil,
|
||||
"author_name"=>"Anonymous User",
|
||||
'avatar_path' => User.default_avatar_fallback,
|
||||
"comment"=>"review comment",
|
||||
"created_at"=>@comment.created_at.as_json,
|
||||
"id"=>@comment.id,
|
||||
"author"=>{}}],
|
||||
"user_id"=>@student1.id,
|
||||
"workflow_state"=>@assessment_request.workflow_state})
|
||||
expect(json[0]).to eq(
|
||||
{
|
||||
"asset_id"=>@submission.id,
|
||||
"asset_type"=>"Submission",
|
||||
"id"=>@assessment_request.id,
|
||||
"submission_comments" => [
|
||||
{
|
||||
"author_id" => nil,
|
||||
"author_name" => "Anonymous User",
|
||||
"avatar_path" => User.default_avatar_fallback,
|
||||
"comment" => "review comment",
|
||||
"created_at" => @comment.created_at.as_json,
|
||||
"edited_at" => nil,
|
||||
"id" => @comment.id,
|
||||
"author" => {}
|
||||
}
|
||||
],
|
||||
"user_id"=>@student1.id,
|
||||
"workflow_state"=>@assessment_request.workflow_state
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'should return peer reviews for a specific submission' do
|
||||
|
|
|
@ -393,35 +393,38 @@ describe UsersController, type: :request do
|
|||
'url' => nil,
|
||||
'user_id' => @sub.user_id,
|
||||
|
||||
'submission_comments' => [{
|
||||
'body' => 'c1',
|
||||
'comment' => 'c1',
|
||||
'author' => {
|
||||
'id' => @teacher.id,
|
||||
'display_name' => 'teacher',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@teacher.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
'submission_comments' => [
|
||||
{
|
||||
'body' => 'c1',
|
||||
'comment' => 'c1',
|
||||
'author' => {
|
||||
'id' => @teacher.id,
|
||||
'display_name' => 'teacher',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@teacher.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'teacher',
|
||||
'author_id' => @teacher.id,
|
||||
'created_at' => @sub.submission_comments[0].created_at.as_json,
|
||||
'edited_at' => nil,
|
||||
'id' => @sub.submission_comments[0].id
|
||||
},
|
||||
'author_name' => 'teacher',
|
||||
'author_id' => @teacher.id,
|
||||
'created_at' => @sub.submission_comments[0].created_at.as_json,
|
||||
'id' => @sub.submission_comments[0].id
|
||||
},
|
||||
{
|
||||
'body' => 'c2',
|
||||
'comment' => 'c2',
|
||||
'author' => {
|
||||
'id' => @user.id,
|
||||
'display_name' => 'User',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@user.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'User',
|
||||
'author_id' => @user.id,
|
||||
'created_at' => @sub.submission_comments[1].created_at.as_json,
|
||||
'id' => @sub.submission_comments[1].id
|
||||
},],
|
||||
|
||||
{
|
||||
'body' => 'c2',
|
||||
'comment' => 'c2',
|
||||
'author' => {
|
||||
'id' => @user.id,
|
||||
'display_name' => 'User',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@user.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'User',
|
||||
'author_id' => @user.id,
|
||||
'created_at' => @sub.submission_comments[1].created_at.as_json,
|
||||
'edited_at' => nil,
|
||||
'id' => @sub.submission_comments[1].id
|
||||
}
|
||||
],
|
||||
'course' => {
|
||||
'name' => @course.name,
|
||||
'end_at' => @course.end_at,
|
||||
|
@ -514,35 +517,38 @@ describe UsersController, type: :request do
|
|||
'url' => nil,
|
||||
'user_id' => @sub.user_id,
|
||||
|
||||
'submission_comments' => [{
|
||||
'body' => 'c1',
|
||||
'comment' => 'c1',
|
||||
'author' => {
|
||||
'id' => @teacher.id,
|
||||
'display_name' => 'teacher',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@teacher.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
'submission_comments' => [
|
||||
{
|
||||
'body' => 'c1',
|
||||
'comment' => 'c1',
|
||||
'author' => {
|
||||
'id' => @teacher.id,
|
||||
'display_name' => 'teacher',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@teacher.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'teacher',
|
||||
'author_id' => @teacher.id,
|
||||
'created_at' => @sub.submission_comments[0].created_at.as_json,
|
||||
'edited_at' => nil,
|
||||
'id' => @sub.submission_comments[0].id
|
||||
},
|
||||
'author_name' => 'teacher',
|
||||
'author_id' => @teacher.id,
|
||||
'created_at' => @sub.submission_comments[0].created_at.as_json,
|
||||
'id' => @sub.submission_comments[0].id
|
||||
},
|
||||
{
|
||||
'body' => 'c2',
|
||||
'comment' => 'c2',
|
||||
'author' => {
|
||||
'id' => @user.id,
|
||||
'display_name' => 'User',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@user.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'User',
|
||||
'author_id' => @user.id,
|
||||
'created_at' => @sub.submission_comments[1].created_at.as_json,
|
||||
'id' => @sub.submission_comments[1].id
|
||||
},],
|
||||
|
||||
{
|
||||
'body' => 'c2',
|
||||
'comment' => 'c2',
|
||||
'author' => {
|
||||
'id' => @user.id,
|
||||
'display_name' => 'User',
|
||||
'html_url' => "http://www.example.com/courses/#{@course.id}/users/#{@user.id}",
|
||||
'avatar_image_url' => User.avatar_fallback_url(nil, request)
|
||||
},
|
||||
'author_name' => 'User',
|
||||
'author_id' => @user.id,
|
||||
'created_at' => @sub.submission_comments[1].created_at.as_json,
|
||||
'edited_at' => nil,
|
||||
'id' => @sub.submission_comments[1].id
|
||||
}
|
||||
],
|
||||
'course' => {
|
||||
'name' => @course.name,
|
||||
'end_at' => @course.end_at,
|
||||
|
|
|
@ -778,6 +778,7 @@ describe 'Submissions API', type: :request do
|
|||
"display_name" => nil
|
||||
},
|
||||
"created_at"=>comment.created_at.as_json,
|
||||
"edited_at" => nil,
|
||||
"author"=>{
|
||||
"id" => @teacher.id,
|
||||
"display_name" => "User",
|
||||
|
@ -1090,6 +1091,7 @@ describe 'Submissions API', type: :request do
|
|||
"display_name" => nil
|
||||
},
|
||||
"created_at"=>comment.reload.created_at.as_json,
|
||||
"edited_at" => nil,
|
||||
"author"=>{
|
||||
"id" => @teacher.id,
|
||||
"display_name" => "User",
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#
|
||||
# Copyright (C) 2017 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
describe Api::V1::SubmissionComment do
|
||||
before(:once) do
|
||||
course = Course.create!
|
||||
@student = User.create!
|
||||
course.enroll_student(@student, active_all: true)
|
||||
assignment = course.assignments.create!
|
||||
submission = assignment.submissions.find_by(user_id: @student)
|
||||
@submission_comment = submission.submission_comments.create!
|
||||
@comment = Object.new.extend(Api::V1::SubmissionComment, Api::V1::User)
|
||||
end
|
||||
|
||||
let(:comment_json) { @comment.submission_comment_json(@submission_comment, @student) }
|
||||
|
||||
describe "#submission_comment_json" do
|
||||
it "includes the 'edited_at' key" do
|
||||
expect(comment_json).to have_key "edited_at"
|
||||
end
|
||||
|
||||
it "'edited_at' is set if the submission comment has been edited" do
|
||||
now = Time.zone.now
|
||||
@submission_comment.edited_at = now
|
||||
expect(comment_json[:edited_at]).to be now
|
||||
end
|
||||
|
||||
it "'edited_at' is nil if the submission comment has not been edited" do
|
||||
expect(comment_json[:edited_at]).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -33,7 +33,7 @@ describe SubmissionComment do
|
|||
end
|
||||
|
||||
it "should create a new instance given valid attributes" do
|
||||
SubmissionComment.create!(@valid_attributes)
|
||||
expect { SubmissionComment.create!(@valid_attributes) }.not_to raise_error
|
||||
end
|
||||
|
||||
describe 'notifications' do
|
||||
|
@ -454,4 +454,37 @@ This text has a http://www.google.com link in it...
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#edited_at" do
|
||||
before(:once) do
|
||||
@comment = SubmissionComment.create!(@valid_attributes)
|
||||
end
|
||||
|
||||
it "is nil for newly-created submission comments" do
|
||||
expect(@comment.edited_at).to be_nil
|
||||
end
|
||||
|
||||
it "remains nil if the submission comment is updated but the 'comment' attribute is unchanged" do
|
||||
@comment.update!(draft: true, hidden: true)
|
||||
expect(@comment.edited_at).to be_nil
|
||||
end
|
||||
|
||||
it "is set if the 'comment' attribute is updated on the submission comment" do
|
||||
now = Time.zone.now
|
||||
Timecop.freeze(now) { @comment.update!(comment: "changing the comment!") }
|
||||
expect(@comment.edited_at).to eql now
|
||||
end
|
||||
|
||||
it "is updated on subsequent changes to the 'comment' attribute" do
|
||||
now = Time.zone.now
|
||||
Timecop.freeze(now) { @comment.update!(comment: "changing the comment!") }
|
||||
|
||||
later = 2.minutes.from_now(now)
|
||||
Timecop.freeze(later) do
|
||||
expect { @comment.update!(comment: "and again, changing it!") }.to change {
|
||||
@comment.edited_at
|
||||
}.from(now).to(later)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue