canvas_webex 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # CanvasWebEx
2
+
3
+ CanvasWebEx is an WebEx plugin for [Instructure
4
+ Canvas](http://instructure.com). It allows users to create and join Cisco
5
+ WebEx conferences directly from their courses.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'canvas_webex'
12
+
13
+ ## Usage
14
+
15
+ CanvasWebEx registers itself as a Canvas plugin and can be configured by
16
+ going to /plugins in your Canvas instance and entering your WebEx information.
17
+
18
+ CanvasWebEx assumes that it's being used inside of a Canvas instance, and
19
+ will explode in strange and beautiful ways if you try to run anything in it
20
+ outside of Canvas.
21
+
22
+ ## Contributing
23
+
24
+ 1. Fork it
25
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
26
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
27
+ 4. Push to the branch (`git push origin my-new-feature`)
28
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1,102 @@
1
+ #
2
+ # Copyright (C) 2013 Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ class CiscoWebexConference < WebConference
20
+
21
+ # Public: Start a new conference and return its key. (required by WebConference)
22
+ #
23
+ # Returns a meeting.
24
+ def initiate_conference
25
+ unless self.conference_key.present?
26
+ webex_meeting = CanvasWebex::Meeting.create(self.title)
27
+ options = {}
28
+ options[:duration] = self.duration || 999999
29
+ self.conference_key = webex_meeting.meeting_key
30
+ save
31
+ end
32
+ self.conference_key
33
+ end
34
+
35
+ # Public: Determine the status of the conference (required by WebConference).
36
+ #
37
+ # Returns conference status as a symbol (either :active or :closed).
38
+ def conference_status
39
+ if meeting || self.started_at.nil?
40
+ :active
41
+ else
42
+ self.close unless self.ended_at
43
+ :closed
44
+ end
45
+ end
46
+
47
+ # Public: Add an admin to the conference and create a meeting URL (required by WebConference).
48
+ #
49
+ # admin - The user to add to the conference as an admin.
50
+ # _ - Included for compatibility w/ web_conference.rb
51
+ #
52
+ # Returns a meeting URL string.
53
+ def admin_join_url(admin, _ = nil)
54
+ if meeting
55
+ meeting.host_url
56
+ end
57
+ end
58
+
59
+ # Public: Add a participant to the conference and create a meeting URL.
60
+ # Make the user a conference admin if they have permissions to create
61
+ # a conference (required by WebConference).
62
+ #
63
+ # user - The user to add to the conference as an admin.
64
+ # _ - Included for compatibility w/ web_conference.rb
65
+ #
66
+ # Returns a meeting URL string.
67
+ def participant_join_url(user, _ = nil)
68
+ if meeting
69
+ if grants_right?(user, nil, :initiate)
70
+ meeting.host_url
71
+ else
72
+ meeting.join_url
73
+ end
74
+ end
75
+ end
76
+
77
+ # Public: List all of the recordings for a meeting
78
+ #
79
+ # Returns an Array of recording hashes, or an empty Array if there are no recordings
80
+ def recordings
81
+ CanvasWebex::Meeting.recordings(self.conference_key)
82
+ end
83
+
84
+ def after_find
85
+ conference_status
86
+ end
87
+
88
+ protected
89
+
90
+ def webex_client
91
+ CanvasWebex.client
92
+ end
93
+
94
+ # Protected: Retrieve the meeting if it is still active
95
+ #
96
+ # Returns the meeting object, or nil if the meeting is ended
97
+ def meeting
98
+ self.conference_key && CanvasWebex::Meeting.retrieve(self.conference_key)
99
+ end
100
+
101
+
102
+ end
@@ -0,0 +1,34 @@
1
+ <% fields_for :settings, OpenObject.new(settings) do |f| %>
2
+ <table class="formtable" style="width: 500px;">
3
+ <tbody>
4
+ <tr>
5
+ <td><%= f.blabel :webex_id, :en => "WebEx ID" %></td>
6
+ <td>
7
+ <%= f.text_field :webex_id, :autocomplete => false %><br>
8
+ </td>
9
+ </tr>
10
+ <tr>
11
+ <td><%= f.blabel :password, :en => "Password" %></td>
12
+ <td>
13
+ <%= f.password_field :password, :autocomplete => false %><br>
14
+ </td>
15
+ </tr>
16
+ <tr>
17
+ <td><%= f.blabel :site_id, "Site ID" %></td>
18
+ <td>
19
+ <%= f.text_field :site_id, :autocomplete => false %><br>
20
+ </td>
21
+ </tr>
22
+ <tr>
23
+ <td><%= f.blabel :site_name, "Site Name" %></td>
24
+ <td>
25
+ <%= f.text_field :site_name, :autocomplete => false %><br>
26
+ <small class="help-text">
27
+ <%= t(:site_name_description, "Site name for your WebEx account,
28
+ if the url is \"https://school.webex.com\" then your site name is 'school'") %>
29
+ </small>
30
+ </td>
31
+ </tr>
32
+ </tbody>
33
+ </table>
34
+ <% end %>
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'canvas_webex/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = 'canvas_webex'
8
+ gem.version = CanvasWebex::VERSION
9
+ gem.authors = ['Nathan Mills']
10
+ gem.email = ['nathanm@instructure.com']
11
+ gem.description = %q{Canvas WebEx is an Cisco Webex plugin for the Instructure Canvas LMS. It allows teachers and administrators to create and launch WEbEx conferences directly from their courses.}
12
+ gem.summary = %q{Cisco WebEx integration for Instructure Canvas (http://instructure.com).}
13
+ gem.homepage = 'http://instructure.com'
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = %w{app lib}
19
+
20
+ gem.add_development_dependency 'rake'
21
+ gem.add_development_dependency 'rspec'
22
+ gem.add_development_dependency 'nokogiri'
23
+ gem.add_development_dependency 'webmock'
24
+ gem.add_development_dependency 'pry'
25
+ end
26
+
@@ -0,0 +1,47 @@
1
+ #
2
+ # Copyright (C) 2012 Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Canvas
20
+ module Plugins
21
+ class CiscoWebex
22
+
23
+ # Public: Bootstrap the gem on app load.
24
+ #
25
+ # Returns nothing.
26
+ def initialize; register; end
27
+
28
+ protected
29
+ # Internal: Register as a plugin with Canvas
30
+ #
31
+ # Returns a Canvas plugin object
32
+ def register
33
+ Canvas::Plugin.register('cisco_webex', :web_conferencing, {
34
+ :name => lambda { t(:name, 'Cisco WebEx') },
35
+ :description => lambda { t(:description, 'Cisco WebEx web conferencing support.') },
36
+ :author => 'Instructure',
37
+ :author_website => 'http://instructure.com',
38
+ :version => CanvasWebex::VERSION,
39
+ :settings_partial => 'plugins/webex_settings',
40
+ :validator => 'CiscoWebexValidator',
41
+ :encrypted_settings => [:password]
42
+ })
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,77 @@
1
+ #
2
+ # Copyright (C) 2013 Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ module Canvas
20
+ module Plugins
21
+ module Validators
22
+ class CiscoWebexValidator
23
+ # Public: An array of allowed plugin settings.
24
+ REQUIRED_KEYS = %w{webex_id password site_id site_name}
25
+
26
+ # Public: Validate setting input for this plugin.
27
+ #
28
+ # settings - A hash of settings params.
29
+ # plugin_setting - A plugin setting object.
30
+ #
31
+ # Returns false on error or a hash of settings options.
32
+ def self.validate(settings, plugin_setting)
33
+ filtered_settings = settings.slice(*REQUIRED_KEYS)
34
+ if all_empty?(filtered_settings)
35
+ # Allow no settings.
36
+ {}
37
+ else
38
+ if valid?(filtered_settings)
39
+ filtered_settings
40
+ else
41
+ plugin_setting.errors.add_to_base(I18n.t('canvas.plugins.errors.all_fields_required', 'All fields are required'))
42
+ false
43
+ end
44
+ end
45
+ end
46
+
47
+ protected
48
+ # Internal: Determine if a given settings hash is empty.
49
+ #
50
+ # settings - A hash of setting params.
51
+ #
52
+ # Returns a boolean.
53
+ def self.all_empty?(settings)
54
+ settings.values.all?(&:blank?)
55
+ end
56
+
57
+ # Internal: Determine if any settings are missing from the given hash.
58
+ #
59
+ # settings - A hash of setting params.
60
+ #
61
+ # Returns a boolean.
62
+ def self.any_empty?(settings)
63
+ settings.values.any?(&:blank?)
64
+ end
65
+
66
+ # Internal: Validate that all required settings are present.
67
+ #
68
+ # settings - The hash of settings to validate.
69
+ #
70
+ # Returns boolean.
71
+ def self.valid?(settings)
72
+ !(any_empty?(settings) || (REQUIRED_KEYS & settings.keys) != REQUIRED_KEYS)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,60 @@
1
+ #
2
+ # Copyright (C) 2013 Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require "canvas_webex/version"
20
+ require "canvas/plugins/validators/cisco_webex_validator"
21
+ require "canvas/plugins/cisco_webex"
22
+ require "canvas_webex/service"
23
+ require "canvas_webex/meeting"
24
+
25
+ module CanvasWebex
26
+ class ConnectionError < StandardError; end
27
+
28
+ # Public: Configure as a Canvas plugin
29
+ #
30
+ # Returns nothing.
31
+ def self.register
32
+ Rails.configuration.to_prepare do
33
+ view_path = File.join(File.dirname(__FILE__), '..', 'app', 'views')
34
+ unless ApplicationController.view_paths.include?(view_path)
35
+ ApplicationController.view_paths.unshift(view_path)
36
+ end
37
+
38
+ require_dependency "models/cisco_webex_conference"
39
+
40
+ Canvas::Plugins::CiscoWebex.new
41
+ end
42
+ end
43
+
44
+ # Public: Find the plugin configuration.
45
+ #
46
+ # Returns a settings hash.
47
+ def self.config
48
+ Canvas::Plugin.find('cisco_webex').settings || {}
49
+ end
50
+
51
+ # Return a cached Connect Service object to make requests with.
52
+ #
53
+ # Returns a CiscoWwebex::Service.
54
+ def self.client
55
+ @client ||= Service.new(*self.config.values_at(:webex_id, :password_dec, :site_id, :site_name, :partner_id))
56
+ end
57
+
58
+ end
59
+
60
+ CanvasWebex.register
@@ -0,0 +1,84 @@
1
+ #
2
+ # Copyright (C) 2013 Instructure, Inc.
3
+ #
4
+ # This file is part of Canvas.
5
+ #
6
+ # Canvas is free software: you can redistribute it and/or modify it under
7
+ # the terms of the GNU Affero General Public License as published by the Free
8
+ # Software Foundation, version 3 of the License.
9
+ #
10
+ # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
11
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
+ # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
+ # details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License along
16
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module CanvasWebex
19
+ class Meeting
20
+
21
+ ATTRIBUTES = [:meeting_key, :conf_name, :start_date, :host_joined, :status]
22
+
23
+ def self.retrieve(meeting_key, client = CanvasWebex.client)
24
+ if response = client.get_meeting(meeting_key)
25
+ Meeting.new(Nokogiri::XML(response.to_xml))
26
+ end
27
+ end
28
+
29
+ def self.create(meeting_name, client = CanvasWebex.client)
30
+ if response = client.create_meeting(meeting_name)
31
+ if meeting_key = response.at_xpath('//meetingkey').try(:text)
32
+ retrieve(meeting_key, client)
33
+ end
34
+ end
35
+ end
36
+
37
+ def host_url(client = CanvasWebex.client)
38
+ if response = client.host_meeting_url(meeting_key, nil)
39
+ response.at_xpath('hostMeetingURL').try(:text)
40
+ end
41
+ end
42
+
43
+ def join_url(client = CanvasWebex.client)
44
+ if response = client.join_meeting_url(meeting_key, nil)
45
+ response.at_xpath('joinMeetingURL').text
46
+ end
47
+ end
48
+
49
+ def self.recordings(meeting_key, client = CanvasWebex.client)
50
+ if response = meeting_key && client.list_recordings(meeting_key)
51
+ response.search('recording').map do |rec_xml|
52
+ recording = {
53
+ recording_id: rec_xml.at_xpath('recordingID').try(:text),
54
+ title: rec_xml.at_xpath('name').try(:text),
55
+ playback_url: rec_xml.at_xpath('streamURL').try(:text)
56
+ }
57
+ if duration = rec_xml.at_xpath('duration').try(:text)
58
+ recording[:duration_minutes] = duration.to_i / 60
59
+ end
60
+ recording
61
+ end
62
+ else
63
+ []
64
+ end
65
+ end
66
+
67
+ # Public: Create a new Meeting
68
+ #
69
+ # meeting_xml - The xml returned for a meeting (must already exist).
70
+ def initialize(meeting_xml)
71
+ @attr_cache = {}
72
+ @xml = meeting_xml
73
+ end
74
+
75
+ def method_missing(meth, *args, &block)
76
+ if ATTRIBUTES.include?(meth)
77
+ @attr_cache[meth] ||= @xml.at_xpath("//*[contains(translate(name(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'), '#{meth.to_s.camelcase(:lower).downcase}')]").try(:text)
78
+ else
79
+ super
80
+ end
81
+ end
82
+
83
+ end
84
+ end