embed poll submissions into poll session

fixes CNVS-13275, CNVS-13297
This commit embeds all submissions when a particular poll session is
requested by authorized users (the creator/teacher of the poll and
relevant poll session.).  It also deletes all submissions and sessions
that belong to a poll when that poll is deleted.

Test plan
Submission embedding
- Create a poll and related poll session
- Create multiple submissions for the poll as students
- As a teacher, you should be able to see the related submissions
  when requesting the poll session via the API

Poll session/submission deletion
- Create a poll and two poll sessions, with two submissions per session
- Delete the poll via the api, it should be deleted successfully

Change-Id: I335f92eb97be095a2ddf6bc730954ed8a14220ef
Reviewed-on: https://gerrit.instructure.com/35456
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Derek DeVries <ddevries@instructure.com>
QA-Review: Caleb Guanzon <cguanzon@instructure.com>
Product-Review: Josh Simpson <jsimpson@instructure.com>
This commit is contained in:
Josh Simpson 2014-05-27 13:20:55 -06:00
parent c1b4b889fa
commit a3a1205e2d
7 changed files with 72 additions and 14 deletions

View File

@ -26,14 +26,25 @@ module Polling
# "required": ["id", "poll_choice"], # "required": ["id", "poll_choice"],
# "properties": { # "properties": {
# "id": { # "id": {
# "description": "The unique identifier for the account role/user assignment.", # "description": "The unique identifier for the poll submission.",
# "example": 1023, # "example": 1023,
# "type": "integer" # "type": "integer"
# }, # },
# "poll_choice_id": { # "poll_choice_id": {
# "description": "The id of the chosen poll choice for this submission.", # "description": "The unique identifier of the poll choice chosen for this submission.",
# "example": 55, # "example": 155,
# "type": "integer" # "type": "integer"
# },
# "user_id": {
# "description": "the unique identifier of the user who submitted this poll submission.",
# "example": 4555,
# "type": "integer"
# },
# "created_at": {
# "description": "The date and time the poll submission was submitted.",
# "example": "2013-11-07T13:16:18Z",
# "type": "string",
# "format": "date-time"
# } # }
# } # }
# } # }

View File

@ -22,8 +22,8 @@ module Polling
belongs_to :user belongs_to :user
has_many :poll_choices, class_name: 'Polling::PollChoice', dependent: :destroy has_many :poll_choices, class_name: 'Polling::PollChoice', dependent: :destroy
has_many :poll_submissions, class_name: 'Polling::PollSubmission' has_many :poll_submissions, class_name: 'Polling::PollSubmission', dependent: :destroy
has_many :poll_sessions, class_name: 'Polling::PollSession' has_many :poll_sessions, class_name: 'Polling::PollSession', dependent: :destroy
validates_presence_of :question, :user validates_presence_of :question, :user
validates_length_of :question, maximum: 255, allow_nil: true validates_length_of :question, maximum: 255, allow_nil: true

View File

@ -21,6 +21,7 @@ module Polling
attr_accessible :text, :poll, :is_correct attr_accessible :text, :poll, :is_correct
belongs_to :poll, class_name: 'Polling::Poll' belongs_to :poll, class_name: 'Polling::Poll'
has_many :poll_submissions, class_name: 'Polling::PollSubmission', dependent: :destroy
validates_presence_of :poll, :text validates_presence_of :poll, :text
validates_length_of :text, maximum: 255, allow_nil: true validates_length_of :text, maximum: 255, allow_nil: true

View File

@ -1,11 +1,16 @@
module Polling module Polling
class PollSessionSerializer < Canvas::APISerializer class PollSessionSerializer < Canvas::APISerializer
root :poll_session attributes :id, :is_published, :has_public_results, :results, :course_id, :course_section_id, :created_at, :poll_id, :poll_submissions
attributes :id, :is_published, :has_public_results, :results, :course_id, :course_section_id, :created_at
def_delegators :object, :results, :poll def_delegators :object, :results, :poll
# has_many relationships with embedded objects doesn't work, so we override it this way
def poll_submissions
@poll_submissions ||= object.poll_submissions.map do |submission|
Polling::PollSubmissionSerializer.new(submission, controller: @controller, scope: @scope, root: false)
end
end
def filter(keys) def filter(keys)
if poll.grants_right?(current_user, session, :update) || object.has_public_results? if poll.grants_right?(current_user, session, :update) || object.has_public_results?
student_keys + teacher_keys student_keys + teacher_keys
@ -17,11 +22,11 @@ module Polling
private private
def teacher_keys def teacher_keys
[:has_public_results, :results] [:has_public_results, :results, :poll_submissions]
end end
def student_keys def student_keys
[:id, :is_published, :course_id, :course_section_id, :created_at] [:id, :is_published, :course_id, :course_section_id, :created_at, :poll_id]
end end
end end
end end

View File

@ -1,7 +1,6 @@
module Polling module Polling
class PollSubmissionSerializer < Canvas::APISerializer class PollSubmissionSerializer < Canvas::APISerializer
root :poll_submission root :poll_submission
attributes :id, :poll_session_id, :poll_choice_id, :user_id, :created_at
attributes :id, :poll_choice_id
end end
end end

View File

@ -95,12 +95,29 @@ describe Polling::PollSessionsController, type: :request do
context "as a teacher" do context "as a teacher" do
it "retrieves the poll session specified even if closed" do it "retrieves the poll session specified even if closed" do
@poll_session.close! @poll_session.close!
@user = @teacher
json = get_show json = get_show
poll_json = json['poll_sessions'].first poll_json = json['poll_sessions'].first
poll_json['id'].should == @poll_session.id.to_s poll_json['id'].should == @poll_session.id.to_s
poll_json['is_published'].should be_false poll_json['is_published'].should be_false
end end
it "embeds the associated poll submissions" do
choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true)
choice2 = @poll.poll_choices.create!(text: 'Choice B', is_correct: false)
2.times { create_submission(choice1) }
1.times { create_submission(choice2) }
@user = @teacher
json = get_show
poll_session_json = json['poll_sessions'].first
poll_session_json.should have_key('poll_submissions')
poll_session_json['poll_submissions'].size.should == 3
end
it "shows the results of a current poll session" do it "shows the results of a current poll session" do
choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true) choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true)
choice2 = @poll.poll_choices.create!(text: 'Choice B', is_correct: false) choice2 = @poll.poll_choices.create!(text: 'Choice B', is_correct: false)
@ -119,6 +136,21 @@ describe Polling::PollSessionsController, type: :request do
end end
context "as a student" do context "as a student" do
it "doesn't embed the associated poll submissions" do
choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true)
choice2 = @poll.poll_choices.create!(text: 'Choice B', is_correct: false)
2.times { create_submission(choice1) }
1.times { create_submission(choice2) }
student = student_in_course(active_user:true).user
@user = student
json = get_show
json.should_not have_key('poll_submissions')
end
context "when has_public_results is false" do context "when has_public_results is false" do
it "doesn't show the results of a current poll session" do it "doesn't show the results of a current poll session" do
choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true) choice1 = @poll.poll_choices.create!(text: 'Choice A', is_correct: true)
@ -342,6 +374,4 @@ describe Polling::PollSessionsController, type: :request do
end end
end end
end end
end end

View File

@ -170,6 +170,16 @@ describe Polling::PollsController, type: :request do
describe 'DELETE destroy' do describe 'DELETE destroy' do
before(:each) do before(:each) do
@poll = @teacher.polls.create!(question: 'An Old Title') @poll = @teacher.polls.create!(question: 'An Old Title')
@choice = @poll.poll_choices.create!(text: 'Blah')
@session = @poll.poll_sessions.create!(course: @course)
@session.publish!
@student = student_in_course(active_user: true).user
@submission = @session.poll_submissions.create!(
user: @student,
poll: @poll,
poll_choice: @choice
)
end end
def delete_destroy def delete_destroy
@ -183,6 +193,7 @@ describe Polling::PollsController, type: :request do
context "as a teacher" do context "as a teacher" do
it "deletes a poll successfully" do it "deletes a poll successfully" do
@user = @teacher
delete_destroy delete_destroy
response.code.should == '204' response.code.should == '204'
@ -193,6 +204,7 @@ describe Polling::PollsController, type: :request do
choice_a = @poll.poll_choices.create!(text: 'choice a') choice_a = @poll.poll_choices.create!(text: 'choice a')
choice_b = @poll.poll_choices.create!(text: 'choice b') choice_b = @poll.poll_choices.create!(text: 'choice b')
@user = @teacher
delete_destroy delete_destroy
response.code.should == '204' response.code.should == '204'
Polling::PollChoice.find_by_id(choice_a.id).should be_nil Polling::PollChoice.find_by_id(choice_a.id).should be_nil