create the media object for submissions and comments if it doesn't exist

Check Kaltura to verify the media id is valid, then create the object,
so that we can track it as we normally do.

fixes #5775

also update some of the submission api documentation around media
comments and file uploads.

test plan: there isn't a UI to show media objects yet, so you'll have to
have console/db access. submit a video/audio submission comment through
the API, then verify that after jobs run, a MediaObject exists for the
media id you gave.

Change-Id: Id0f5b4cdc23330ea952e674df4fc0d1f1c81bf23
Reviewed-on: https://gerrit.instructure.com/12245
Reviewed-by: Simon Williams <simon@instructure.com>
Tested-by: Jenkins <jenkins@instructure.com>
This commit is contained in:
Brian Palmer 2012-07-13 15:51:26 -06:00
parent 1edc78ea73
commit 6c8efd8322
8 changed files with 92 additions and 16 deletions

View File

@ -181,7 +181,7 @@ class SubmissionsApiController < ApplicationController
end end
end end
# @API Grade a submission # @API Grade or comment on a submission
# #
# Comment on and/or update the grading for a student's assignment submission. # Comment on and/or update the grading for a student's assignment submission.
# If any submission or rubric_assessment arguments are provided, the user # If any submission or rubric_assessment arguments are provided, the user
@ -192,6 +192,13 @@ class SubmissionsApiController < ApplicationController
# #
# @argument comment[group_comment] [Boolean] Whether or not this comment should be sent to the entire group (defaults to false). Ignored if this is not a group assignment or if no text_comment is provided. # @argument comment[group_comment] [Boolean] Whether or not this comment should be sent to the entire group (defaults to false). Ignored if this is not a group assignment or if no text_comment is provided.
# #
# @argument comment[media_comment_id] Add an audio/video comment to the submission.
# Media comments can be added via this API, however, note that there
# is not yet an API to generate or list existing media comments, so this
# functionality is currently of limited use.
#
# @argument comment[media_comment_type] ["audio"|"video"] The type of media comment being added.
#
# @argument submission[posted_grade] Assign a score to the submission, # @argument submission[posted_grade] Assign a score to the submission,
# updating both the "score" and "grade" fields on the submission record. # updating both the "score" and "grade" fields on the submission record.
# This parameter can be passed in a few different formats: # This parameter can be passed in a few different formats:
@ -278,11 +285,6 @@ class SubmissionsApiController < ApplicationController
if comment.is_a?(Hash) if comment.is_a?(Hash)
comment = { comment = {
:comment => comment[:text_comment], :author => @current_user }.merge( :comment => comment[:text_comment], :author => @current_user }.merge(
# Undocumented API feature: adding media comments given the kaltura
# media id. Eventually we'll expose a public API for media comments,
# but we need to implement a way to abstract it away from kaltura and
# make it generic. This will probably involve a proxy outside of
# rails.
comment.slice(:media_comment_id, :media_comment_type, :group_comment) comment.slice(:media_comment_id, :media_comment_type, :group_comment)
).with_indifferent_access ).with_indifferent_access
@assignment.update_submission(@submission.user, comment) @assignment.update_submission(@submission.user, comment)

View File

@ -239,8 +239,7 @@ class SubmissionsController < ApplicationController
# one or more previously uploaded files residing in the submitting user's # one or more previously uploaded files residing in the submitting user's
# files section (or the group's files section, for group assignments). # files section (or the group's files section, for group assignments).
# #
# There is not yet an API for listing a user's or group's files, or # To upload a new file to submit, see the submissions {api:SubmissionsApiController#create_file Upload a file API}.
# uploading files for submission. This API is coming soon.
# #
# Requires a submission_type of "online_upload". # Requires a submission_type of "online_upload".
# #

View File

@ -155,7 +155,27 @@ class MediaObject < ActiveRecord::Base
build_media_objects(res, root_account_id) build_media_objects(res, root_account_id)
end end
end end
def self.media_id_exists?(media_id)
client = Kaltura::ClientV3.new
client.startSession(Kaltura::SessionType::ADMIN)
info = client.mediaGet(media_id)
return !!info[:id]
end
def self.ensure_media_object(media_id, create_opts = {})
if !by_media_id(media_id).any?
self.send_later_enqueue_args(:create_if_id_exists, { :priority => Delayed::LOW_PRIORITY }, media_id, create_opts)
end
end
# typically call this in a delayed job, since it has to contact kaltura
def self.create_if_id_exists(media_id, create_opts = {})
if media_id_exists?(media_id) && !by_media_id(media_id).any?
create!(create_opts.merge(:media_id => media_id))
end
end
def update_title_on_kaltura def update_title_on_kaltura
client = Kaltura::ClientV3.new client = Kaltura::ClientV3.new
client.startSession(Kaltura::SessionType::ADMIN) client.startSession(Kaltura::SessionType::ADMIN)
@ -251,7 +271,6 @@ class MediaObject < ActiveRecord::Base
def data def data
self.read_attribute(:data) || self.write_attribute(:data, {}) self.read_attribute(:data) || self.write_attribute(:data, {})
end end
def viewed! def viewed!
send_later(:updated_viewed_at_and_retrieve_details, Time.now) if !self.data[:last_viewed_at] || self.data[:last_viewed_at] > 1.hour.ago send_later(:updated_viewed_at_and_retrieve_details, Time.now) if !self.data[:last_viewed_at] || self.data[:last_viewed_at] > 1.hour.ago

View File

@ -106,6 +106,7 @@ class Submission < ActiveRecord::Base
after_save :update_final_score after_save :update_final_score
after_save :submit_to_turnitin_later after_save :submit_to_turnitin_later
after_save :update_admins_if_just_submitted after_save :update_admins_if_just_submitted
after_save :check_for_media_object
after_save :update_quiz_submission after_save :update_quiz_submission
def self.needs_grading_trigger_sql def self.needs_grading_trigger_sql
@ -481,6 +482,15 @@ class Submission < ActiveRecord::Base
end end
true true
end end
def check_for_media_object
if self.media_comment_id.present? && self.media_comment_id_changed?
MediaObject.ensure_media_object(self.media_comment_id, {
:user => self.user,
:context => self.user,
})
end
end
def submission_history def submission_history
res = [] res = []

View File

@ -27,8 +27,6 @@ class SubmissionComment < ActiveRecord::Base
has_many :associated_attachments, :class_name => 'Attachment', :as => :context has_many :associated_attachments, :class_name => 'Attachment', :as => :context
has_many :submission_comment_participants, :dependent => :destroy has_many :submission_comment_participants, :dependent => :destroy
has_many :messages, :as => :context, :dependent => :destroy has_many :messages, :as => :context, :dependent => :destroy
# too bad, this wont work.
# has_many :comments_in_group, :class_name => "SubmissionComment", :foreign_key => "group_comment_id", :primary_key => "group_comment_id", :dependent => :destroy, :conditions => lambda{|sc| "id !=#{sc.id}"}
validates_length_of :comment, :maximum => maximum_text_length, :allow_nil => true, :allow_blank => true validates_length_of :comment, :maximum => maximum_text_length, :allow_nil => true, :allow_blank => true
validates_length_of :comment, :minimum => 1, :allow_nil => true, :allow_blank => true validates_length_of :comment, :minimum => 1, :allow_nil => true, :allow_blank => true
@ -37,6 +35,7 @@ class SubmissionComment < ActiveRecord::Base
before_save :infer_details before_save :infer_details
after_save :update_submission after_save :update_submission
after_save :check_for_media_object
after_destroy :delete_other_comments_in_this_group after_destroy :delete_other_comments_in_this_group
after_create :update_participants after_create :update_participants
after_create { |c| c.submission.create_or_update_conversations!(:create) if c.send_to_conversations? } after_create { |c| c.submission.create_or_update_conversations!(:create) if c.send_to_conversations? }
@ -62,6 +61,15 @@ class SubmissionComment < ActiveRecord::Base
self.media_comment_id && self.media_comment_type self.media_comment_id && self.media_comment_type
end end
def check_for_media_object
if self.media_comment? && self.media_comment_id_changed?
MediaObject.ensure_media_object(self.media_comment_id, {
:user => self.author,
:context => self.author,
})
end
end
on_create_send_to_streams do on_create_send_to_streams do
if self.submission if self.submission
if self.author_id == self.submission.user_id if self.author_id == self.submission.user_id
@ -209,8 +217,4 @@ class SubmissionComment < ActiveRecord::Base
named_scope :for_context, lambda{|context| named_scope :for_context, lambda{|context|
{:conditions => ['submission_comments.context_id = ? AND submission_comments.context_type = ?', context.id, context.class.to_s] } {:conditions => ['submission_comments.context_id = ? AND submission_comments.context_type = ?', context.id, context.class.to_s] }
} }
# protected :infer_details
# named_scope :for, lambda {|user|
# {:conditions => ['(submission_comments.recipient_id IS NULL OR submission_comments.recipient_id = ?)', (user ? user.id : 0)]}
# }
end end

View File

@ -50,4 +50,31 @@ describe MediaObject do
@a2.reload.file_state.should == 'available' @a2.reload.file_state.should == 'available'
end end
end end
describe ".ensure_media_object" do
it "should not create if the media object exists already" do
MediaObject.create!(:context => user, :media_id => "test")
expect {
MediaObject.ensure_media_object("test", {})
}.to change(Delayed::Job, :count).by(0)
end
it "should not create if the media id doesn't exist in kaltura" do
MediaObject.expects(:media_id_exists?).with("test").returns(false)
expect {
MediaObject.ensure_media_object("test", {})
run_jobs
}.to change(MediaObject, :count).by(0)
end
it "should create the media object" do
MediaObject.expects(:media_id_exists?).with("test").returns(true)
expect {
MediaObject.ensure_media_object("test", { :context => user })
run_jobs
}.to change(MediaObject, :count).by(1)
obj = MediaObject.by_media_id("test").first
obj.context.should == @user
end
end
end end

View File

@ -158,6 +158,14 @@ This text has a http://www.google.com link in it...
@item.data.submission_comments[0].formatted_body.should eql(@comment.formatted_body(250)) @item.data.submission_comments[0].formatted_body.should eql(@comment.formatted_body(250))
end end
it "should ensure the media object exists" do
assignment_model
se = @course.enroll_student(user)
@submission = @assignment.submit_homework(se.user, :body => 'some message')
MediaObject.expects(:ensure_media_object).with("fake", { :context => se.user, :user => se.user })
@comment = @submission.add_comment(:author => se.user, :media_comment_type => 'audio', :media_comment_id => 'fake')
end
context "conversations" do context "conversations" do
before do before do
assignment_model assignment_model

View File

@ -104,6 +104,13 @@ describe Submission do
@submission.conversation_groups.should eql @submission.conversation_groups.uniq @submission.conversation_groups.should eql @submission.conversation_groups.uniq
end end
it "should ensure the media object exists" do
assignment_model
se = @course.enroll_student(user)
MediaObject.expects(:ensure_media_object).with("fake", { :context => se.user, :user => se.user })
@submission = @assignment.submit_homework(se.user, :media_comment_id => "fake", :media_comment_type => "audio")
end
context "Discussion Topic" do context "Discussion Topic" do
it "should use correct date for its submitted_at value" do it "should use correct date for its submitted_at value" do
course_with_student_logged_in(:active_all => true) course_with_student_logged_in(:active_all => true)