Skip to content

Commit a747d30

Browse files
mcwqy9JoelHough
authored andcommitted
Canvas API to mark a web conference as having a prepared recording
Fixes: CNVS-19783 Test Plan: Run migrations Create a new web conference. Get the conference key from a rails console: conf_key = WebConference.last.conference_key Get the secret key: secret = WebConference.last.config[:secret_dec] Put together a signed payload like this: signed = JWT.encode({meeting_id: conf_key}, secret) Then post it to your localhost like this (not in the rails console): curl --data "signed_parameters={the string you got handed when you signed the payload}" http://localhost:3000/api/v1/courses/{your course id}/conferences/{your conference id}/recording_ready If you look at the rails server you should see the html of the notification email fly by. Change-Id: I87cf9fc229130c2e23529c47856a66aa8e57c697 Reviewed-on: https://gerrit.instructure.com/51813 Reviewed-by: Joel Hough <joel@instructure.com> Tested-by: Jenkins QA-Review: Derek Hansen <dhansen@instructure.com> Product-Review: Joel Hough <joel@instructure.com>
1 parent badeee7 commit a747d30

18 files changed

Lines changed: 298 additions & 90 deletions

app/coffeescripts/notifications/NotificationGroupMappings.coffee

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ define [
1313
# gets the I18n version of the group name. The display text used for the items gets set through the
1414
# ProfileController#communication. The values are defined in Notification#category_display_name.
1515
@groups =
16-
Course: ['due_date', 'grading_policies', 'course_content', 'files', 'announcement', 'announcement_created_by_you', 'announcement_reply', 'grading', 'invitation',
16+
Course: ['due_date', 'grading_policies', 'course_content', 'files', 'announcement',
17+
'announcement_created_by_you', 'announcement_reply', 'grading', 'invitation',
1718
'all_submissions', 'late_grading', 'submission_comment']
1819
Discussions: ['discussion', 'discussion_entry']
1920
Communication: ['added_to_conversation', 'conversation_message', 'conversation_created']
@@ -22,6 +23,7 @@ define [
2223
Parent: []
2324
Groups: ['membership_update']
2425
Alerts: ['other']
26+
Conferences: ['recording_ready']
2527

2628
# Get the I18n display text to use for the group name.
2729
getGroupDisplayName: (groupName) =>
@@ -34,4 +36,5 @@ define [
3436
when 'Groups' then I18n.t('groups.groups', 'Groups')
3537
when 'Alerts' then I18n.t('groups.alerts', 'Alerts')
3638
when 'Other' then I18n.t('groups.admin', 'Administrative')
39+
when 'Conferences' then I18n.t('groups.conferences', 'Conferences')
3740
else I18n.t('groups.other', 'Other')

app/controllers/conferences_controller.rb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,12 @@ class ConferencesController < ApplicationController
136136
include Api::V1::Conferences
137137

138138
before_filter :require_context
139-
add_crumb(proc{ t '#crumbs.conferences', "Conferences"}) { |c| c.send(:named_context_url, c.instance_variable_get("@context"), :context_conferences_url) }
139+
skip_before_filter :load_user, :only => [:recording_ready]
140+
141+
add_crumb(proc{ t '#crumbs.conferences', "Conferences"}) do |c|
142+
c.send(:named_context_url, c.instance_variable_get("@context"), :context_conferences_url)
143+
end
144+
140145
before_filter { |c| c.active_tab = "conferences" }
141146
before_filter :require_config
142147
before_filter :reject_student_view_student
@@ -285,6 +290,21 @@ def join
285290
redirect_to named_context_url(@context, :context_conferences_url)
286291
end
287292

293+
def recording_ready
294+
secret = @conference.config[:secret_dec]
295+
begin
296+
signed_params = Canvas::Security.decode_jwt(params[:signed_parameters], [secret])
297+
if signed_params[:meeting_id] == @conference.conference_key
298+
@conference.recording_ready!
299+
render json: [], status: :accepted
300+
else
301+
render json: signed_id_invalid_json, status: :unprocessable_entity
302+
end
303+
rescue Canvas::Security::InvalidToken
304+
render json: invalid_jwt_token_json, status: :unauthorized
305+
end
306+
end
307+
288308
def close
289309
if authorized_action(@conference, @current_user, :close)
290310
unless @conference.active?

app/messages/notification_types.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,8 @@
246246
notifications:
247247
- name: Summaries
248248
delay_for: 0
249+
250+
- category: Recording Ready
251+
notifications:
252+
- name: Web Conference Recording Ready
253+
delay_for: 0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<% define_content :link do %>
2+
<%= polymorphic_url([asset.context, :conferences]) %>
3+
<% end %>
4+
5+
<% define_content :subject do %>
6+
<%= t :subject, "Web Conference Recording Ready: %{name}", :name => asset.context.name %>
7+
<% end %>
8+
9+
<%= t :body, "Your recording of %{title} for %{name} is ready.", :title => asset.title, :name => asset.context.name %>
10+
11+
<%= t :details_link, "You can see the details here: %{link}", :link => content(:link) %>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<% define_content :link do %>
2+
<%= polymorphic_url([asset.context, :conferences]) %>
3+
<% end %>
4+
5+
<% define_content :subject do %>
6+
<%= t :subject, "Web Conference Recording Ready: %{name}", :name => asset.context.name %>
7+
<% end %>
8+
9+
<% define_content :footer_link do %>
10+
<a href="<%= content(:link) %>">
11+
<%= t :details_link, "Click here to see the details"%>
12+
</a>
13+
<% end %>
14+
15+
<p><%= t :body, "Your recording of %{title} for %{name} is ready.", :title => asset.title, :name => asset.context.name %></p>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<%= t :body, "Your recording of %{title} for %{name} is ready.", :title => asset.title, :name => asset.context.name %>
2+
3+
<%= t :link_message, "More info at %{url}", :url => HostUrl.context_host(asset.context) %>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<% define_content :link do %>
2+
<%= polymorphic_url([asset.context, :conferences]) %>
3+
<% end %>
4+
5+
<% define_content :subject do %>
6+
<%= t :subject, "Web Conference Recording Ready: %{name}", :name => asset.context.name %>
7+
<% end %>
8+
9+
<%= t :body, "Your recording of %{title} for %{name} is ready.", :title => asset.title, :name => asset.context.name %>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<% define_content :link do -%>
2+
<%= polymorphic_url([asset.context, :conferences]) %>
3+
<% end -%>
4+
<%= t :tweet, "Canvas Alert - Recording ready: %{title}, %{name}", :title => asset.title, :name => asset.context.name %>

app/models/big_blue_button_conference.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
require 'nokogiri'
2020

2121
class BigBlueButtonConference < WebConference
22+
include ActionDispatch::Routing::PolymorphicRoutes
23+
include CanvasRails::Application.routes.url_helpers
2224
after_destroy :end_meeting
2325
after_destroy :delete_all_recordings
2426

@@ -51,13 +53,21 @@ def initiate_conference
5153
:moderatorPW => settings[:admin_key],
5254
:logoutURL => (settings[:default_return_url] || "http://www.instructure.com"),
5355
:record => settings[:record] ? "true" : "false",
54-
:welcome => settings[:record] ? t("This conference may be recorded.") : ""
56+
:welcome => settings[:record] ? t("This conference may be recorded.") : "",
57+
"meta_canvas-recording-ready-url" => recording_ready_url
5558
}) or return nil
5659
@conference_active = true
5760
save
5861
conference_key
5962
end
6063

64+
def recording_ready_url
65+
polymorphic_url([:api_v1, context, :conferences, :recording_ready],
66+
conference_id: self.id,
67+
protocol: HostUrl.protocol,
68+
host: HostUrl.context_host(self))
69+
end
70+
6171
def conference_status
6272
if (result = send_request(:isMeetingRunning, :meetingID => conference_key)) && result[:running] == 'true'
6373
:active

app/models/notification.rb

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Notification < ActiveRecord::Base
6060
state :active do
6161
event :deactivate, :transitions_to => :inactive
6262
end
63-
63+
6464
state :inactive do
6565
event :reactivate, :transitions_to => :active
6666
end
@@ -103,7 +103,7 @@ def infer_default_content
103103
def create_message(asset, to_list, options={})
104104
return NotificationMessageCreator.new(self, asset, options.merge(:to_list => to_list)).create_message
105105
end
106-
106+
107107
def category_spaceless
108108
(self.category || "None").gsub(/\s/, "_")
109109
end
@@ -128,35 +128,35 @@ def sort_order
128128
9
129129
end
130130
end
131-
131+
132132
def self.types_to_show_in_feed
133133
TYPES_TO_SHOW_IN_FEED
134134
end
135-
135+
136136
def show_in_feed?
137137
self.category == "TestImmediately" || Notification.types_to_show_in_feed.include?(self.name)
138138
end
139-
139+
140140
def registration?
141141
return self.category == "Registration"
142142
end
143143

144144
def migration?
145145
return self.category == "Migration"
146146
end
147-
147+
148148
def summarizable?
149149
return !self.registration? && !self.migration?
150150
end
151-
151+
152152
def dashboard?
153153
return ["Migration", "Registration", "Summaries", "Alert"].include?(self.category) == false
154154
end
155-
155+
156156
def category_slug
157157
(self.category || "").gsub(/ /, "_").gsub(/[^\w]/, "").downcase
158158
end
159-
159+
160160
# if user is given, categories that aren't relevant to that user will be
161161
# filtered out.
162162
def self.dashboard_categories(user = nil)
@@ -183,8 +183,8 @@ def related_user_setting(user)
183183
setting[:id] = "cat_#{self.id}_option" if setting
184184
setting
185185
end
186-
187-
def default_frequency(user = nil)
186+
187+
def default_frequency(_user = nil)
188188
# user arg is used in plugins
189189
case category
190190
when 'All Submissions'
@@ -249,11 +249,13 @@ def default_frequency(user = nil)
249249
FREQ_IMMEDIATELY
250250
when 'Conversation Created'
251251
FREQ_NEVER
252+
when 'Recording Ready'
253+
FREQ_IMMEDIATELY
252254
else
253255
FREQ_DAILY
254256
end
255257
end
256-
258+
257259
# TODO i18n: show the localized notification name in the dashboard (or
258260
# wherever), even if we continue to store the english string in the db
259261
# (it's actually just the titleized message template filename)
@@ -326,6 +328,7 @@ def names
326328
t 'names.appointment_reserved_by_user', 'Appointment Reserved By User'
327329
t 'names.appointment_reserved_for_user', 'Appointment Reserved For User'
328330
t 'names.submission_needs_grading', 'Submission Needs Grading'
331+
t 'names.web_conference_recording_ready', 'Web Conference Recording Ready'
329332
end
330333

331334
# TODO: i18n ... show these anywhere we show the category today
@@ -352,63 +355,66 @@ def category_names
352355
t 'categories.migration', 'Migration'
353356
t 'categories.reminder', 'Reminder'
354357
t 'categories.submission_comment', 'Submission Comment'
358+
t 'categories.recording_ready', 'Recording Ready'
355359
end
356360

357361
# Translatable display text to use when representing the category to the user.
358362
# NOTE: If you add a new notification category, update the mapping file for groupings to show up
359363
# on notification preferences page. /app/coffeescripts/notifications/NotificationGroupMappings.coffee
360364
def category_display_name
361365
case category
362-
when 'Announcement'
363-
t(:announcement_display, 'Announcement')
364-
when 'Announcement Created By You'
365-
t(:announcement_created_by_you_display, 'Announcement Created By You')
366-
when 'Course Content'
367-
t(:course_content_display, 'Course Content')
368-
when 'Files'
369-
t(:files_display, 'Files')
370-
when 'Discussion'
371-
t(:discussion_display, 'Discussion')
372-
when 'DiscussionEntry'
373-
t(:discussion_post_display, 'Discussion Post')
374-
when 'Due Date'
375-
t(:due_date_display, 'Due Date')
376-
when 'Grading'
377-
t(:grading_display, 'Grading')
378-
when 'Late Grading'
379-
t(:late_grading_display, 'Late Grading')
380-
when 'All Submissions'
381-
t(:all_submissions_display, 'All Submissions')
382-
when 'Submission Comment'
383-
t(:submission_comment_display, 'Submission Comment')
384-
when 'Grading Policies'
385-
t(:grading_policies_display, 'Grading Policies')
386-
when 'Invitation'
387-
t(:invitation_display, 'Invitation')
388-
when 'Other'
389-
t(:other_display, 'Administrative Notifications')
390-
when 'Calendar'
391-
t(:calendar_display, 'Calendar')
392-
when 'Student Appointment Signups'
393-
t(:student_appointment_display, 'Student Appointment Signups')
394-
when 'Appointment Availability'
395-
t(:appointment_availability_display, 'Appointment Availability')
396-
when 'Appointment Signups'
397-
t(:appointment_signups_display, 'Appointment Signups')
398-
when 'Appointment Cancelations'
399-
t(:appointment_cancelations_display, 'Appointment Cancelations')
400-
when 'Conversation Message'
401-
t(:conversation_message_display, 'Conversation Message')
402-
when 'Added To Conversation'
403-
t(:added_to_conversation_display, 'Added To Conversation')
404-
when 'Conversation Created'
405-
t(:conversation_created_display, 'Conversations Created By Me')
406-
when 'Membership Update'
407-
t(:membership_update_display, 'Membership Update')
408-
when 'Reminder'
409-
t(:reminder_display, 'Reminder')
410-
else
411-
t(:missing_display_display, "For %{category} notifications", :category => category)
366+
when 'Announcement'
367+
t(:announcement_display, 'Announcement')
368+
when 'Announcement Created By You'
369+
t(:announcement_created_by_you_display, 'Announcement Created By You')
370+
when 'Course Content'
371+
t(:course_content_display, 'Course Content')
372+
when 'Files'
373+
t(:files_display, 'Files')
374+
when 'Discussion'
375+
t(:discussion_display, 'Discussion')
376+
when 'DiscussionEntry'
377+
t(:discussion_post_display, 'Discussion Post')
378+
when 'Due Date'
379+
t(:due_date_display, 'Due Date')
380+
when 'Grading'
381+
t(:grading_display, 'Grading')
382+
when 'Late Grading'
383+
t(:late_grading_display, 'Late Grading')
384+
when 'All Submissions'
385+
t(:all_submissions_display, 'All Submissions')
386+
when 'Submission Comment'
387+
t(:submission_comment_display, 'Submission Comment')
388+
when 'Grading Policies'
389+
t(:grading_policies_display, 'Grading Policies')
390+
when 'Invitation'
391+
t(:invitation_display, 'Invitation')
392+
when 'Other'
393+
t(:other_display, 'Administrative Notifications')
394+
when 'Calendar'
395+
t(:calendar_display, 'Calendar')
396+
when 'Student Appointment Signups'
397+
t(:student_appointment_display, 'Student Appointment Signups')
398+
when 'Appointment Availability'
399+
t(:appointment_availability_display, 'Appointment Availability')
400+
when 'Appointment Signups'
401+
t(:appointment_signups_display, 'Appointment Signups')
402+
when 'Appointment Cancelations'
403+
t(:appointment_cancelations_display, 'Appointment Cancelations')
404+
when 'Conversation Message'
405+
t(:conversation_message_display, 'Conversation Message')
406+
when 'Added To Conversation'
407+
t(:added_to_conversation_display, 'Added To Conversation')
408+
when 'Conversation Created'
409+
t(:conversation_created_display, 'Conversations Created By Me')
410+
when 'Membership Update'
411+
t(:membership_update_display, 'Membership Update')
412+
when 'Reminder'
413+
t(:reminder_display, 'Reminder')
414+
when 'Recording Ready'
415+
t(:recording_ready_display, 'Recording Ready')
416+
else
417+
t(:missing_display_display, "For %{category} notifications", :category => category)
412418
end
413419
end
414420

@@ -511,6 +517,8 @@ def category_description
511517
t(:added_to_conversation_description, 'You are added to a conversation')
512518
when 'Conversation Created'
513519
t(:conversation_created_description, 'You created a conversation')
520+
when 'Recording Ready'
521+
t(:web_conference_recording_ready, 'A conference recording is ready')
514522
when 'Membership Update'
515523
mt(:membership_update_description, <<-EOS)
516524
*Admin only: pending enrollment activated*

0 commit comments

Comments
 (0)