rtunesu 0.2.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/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +77 -0
- data/README.txt +38 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +75 -0
- data/config/requirements.rb +15 -0
- data/lib/multipart.rb +53 -0
- data/lib/rtunesu/connection.rb +111 -0
- data/lib/rtunesu/document.rb +84 -0
- data/lib/rtunesu/entities/course.rb +8 -0
- data/lib/rtunesu/entities/division.rb +16 -0
- data/lib/rtunesu/entities/group.rb +8 -0
- data/lib/rtunesu/entities/permission.rb +7 -0
- data/lib/rtunesu/entities/section.rb +15 -0
- data/lib/rtunesu/entities/site.rb +7 -0
- data/lib/rtunesu/entities/theme.rb +4 -0
- data/lib/rtunesu/entities/track.rb +13 -0
- data/lib/rtunesu/entity.rb +154 -0
- data/lib/rtunesu/user.rb +26 -0
- data/lib/rtunesu/version.rb +9 -0
- data/lib/rtunesu.rb +25 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/spec/connection_spec.rb +53 -0
- data/spec/document_spec.rb +16 -0
- data/spec/documents/add_spec.rb +41 -0
- data/spec/documents/delete_spec.rb +30 -0
- data/spec/documents/merge_spec.rb +30 -0
- data/spec/documents/show_tree_spec.rb +16 -0
- data/spec/entities/course_spec.rb +47 -0
- data/spec/entities/division_spec.rb +8 -0
- data/spec/entities/group_spec.rb +8 -0
- data/spec/entities/permission_spec.rb +8 -0
- data/spec/entities/section_spec.rb +8 -0
- data/spec/entities/site_spec.rb +8 -0
- data/spec/entities/track_spec.rb +8 -0
- data/spec/entity_spec.rb +108 -0
- data/spec/fixtures/add_course.xml +26 -0
- data/spec/fixtures/add_division.xml +26 -0
- data/spec/fixtures/add_group.xml +27 -0
- data/spec/fixtures/add_permission.xml +12 -0
- data/spec/fixtures/add_section.xml +34 -0
- data/spec/fixtures/add_track.xml +19 -0
- data/spec/fixtures/delete_course.xml +8 -0
- data/spec/fixtures/delete_division.xml +8 -0
- data/spec/fixtures/delete_group.xml +8 -0
- data/spec/fixtures/delete_permission.xml +9 -0
- data/spec/fixtures/delete_section.xml +8 -0
- data/spec/fixtures/delete_track.xml +7 -0
- data/spec/fixtures/merge_course.xml +38 -0
- data/spec/fixtures/merge_division.xml +47 -0
- data/spec/fixtures/merge_group.xml +29 -0
- data/spec/fixtures/merge_permission.xml +12 -0
- data/spec/fixtures/merge_section.xml +36 -0
- data/spec/fixtures/merge_site.xml +31 -0
- data/spec/fixtures/merge_track.xml +18 -0
- data/spec/fixtures/requests/add_coures_request.xml +0 -0
- data/spec/fixtures/responses/generic_entity_response.xml +17 -0
- data/spec/fixtures/responses/show_tree_course.xml +676 -0
- data/spec/fixtures/show_tree.xml +273 -0
- data/spec/fixtures/update_group.xml +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/user_spec.rb +18 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +17 -0
- data/website/index.html +141 -0
- data/website/index.txt +83 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.html.erb +48 -0
- metadata +144 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Trek Glowacki
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
lib/multipart.rb
|
9
|
+
lib/rtunesu.rb
|
10
|
+
lib/rtunesu/connection.rb
|
11
|
+
lib/rtunesu/document.rb
|
12
|
+
lib/rtunesu/entities/course.rb
|
13
|
+
lib/rtunesu/entities/division.rb
|
14
|
+
lib/rtunesu/entities/group.rb
|
15
|
+
lib/rtunesu/entities/permission.rb
|
16
|
+
lib/rtunesu/entities/section.rb
|
17
|
+
lib/rtunesu/entities/site.rb
|
18
|
+
lib/rtunesu/entities/track.rb
|
19
|
+
lib/rtunesu/entities/theme.rb
|
20
|
+
lib/rtunesu/entity.rb
|
21
|
+
lib/rtunesu/user.rb
|
22
|
+
lib/rtunesu/version.rb
|
23
|
+
script/console
|
24
|
+
script/destroy
|
25
|
+
script/generate
|
26
|
+
script/txt2html
|
27
|
+
setup.rb
|
28
|
+
spec/connection_spec.rb
|
29
|
+
spec/document_spec.rb
|
30
|
+
spec/documents/add_spec.rb
|
31
|
+
spec/documents/delete_spec.rb
|
32
|
+
spec/documents/merge_spec.rb
|
33
|
+
spec/documents/show_tree_spec.rb
|
34
|
+
spec/entities/course_spec.rb
|
35
|
+
spec/entities/division_spec.rb
|
36
|
+
spec/entities/group_spec.rb
|
37
|
+
spec/entities/permission_spec.rb
|
38
|
+
spec/entities/section_spec.rb
|
39
|
+
spec/entities/site_spec.rb
|
40
|
+
spec/entities/track_spec.rb
|
41
|
+
spec/entity_spec.rb
|
42
|
+
spec/fixtures/add_course.xml
|
43
|
+
spec/fixtures/add_division.xml
|
44
|
+
spec/fixtures/add_group.xml
|
45
|
+
spec/fixtures/add_permission.xml
|
46
|
+
spec/fixtures/add_section.xml
|
47
|
+
spec/fixtures/add_track.xml
|
48
|
+
spec/fixtures/delete_course.xml
|
49
|
+
spec/fixtures/delete_division.xml
|
50
|
+
spec/fixtures/delete_group.xml
|
51
|
+
spec/fixtures/delete_permission.xml
|
52
|
+
spec/fixtures/delete_section.xml
|
53
|
+
spec/fixtures/delete_track.xml
|
54
|
+
spec/fixtures/merge_course.xml
|
55
|
+
spec/fixtures/merge_division.xml
|
56
|
+
spec/fixtures/merge_group.xml
|
57
|
+
spec/fixtures/merge_permission.xml
|
58
|
+
spec/fixtures/merge_section.xml
|
59
|
+
spec/fixtures/merge_site.xml
|
60
|
+
spec/fixtures/merge_track.xml
|
61
|
+
spec/fixtures/requests/add_coures_request.xml
|
62
|
+
spec/fixtures/responses/generic_entity_response.xml
|
63
|
+
spec/fixtures/responses/show_tree_course.xml
|
64
|
+
spec/fixtures/show_tree.xml
|
65
|
+
spec/fixtures/update_group.xml
|
66
|
+
spec/spec.opts
|
67
|
+
spec/spec_helper.rb
|
68
|
+
spec/user_spec.rb
|
69
|
+
tasks/deployment.rake
|
70
|
+
tasks/environment.rake
|
71
|
+
tasks/rspec.rake
|
72
|
+
tasks/website.rake
|
73
|
+
website/index.html
|
74
|
+
website/index.txt
|
75
|
+
website/javascripts/rounded_corners_lite.inc.js
|
76
|
+
website/stylesheets/screen.css
|
77
|
+
website/template.html.erb
|
data/README.txt
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= RTunesU
|
2
|
+
|
3
|
+
== DESCRIPTION:
|
4
|
+
RTunesU is a ruby library for accessing Apple's iTunes U Webservices to integrate your education institutions iTunes U account into ruby applications
|
5
|
+
|
6
|
+
== FEATURES/PROBLEMS:
|
7
|
+
- TODO: file uploading
|
8
|
+
|
9
|
+
== SYNOPSIS:
|
10
|
+
|
11
|
+
== REQUIREMENTS:
|
12
|
+
|
13
|
+
== INSTALL:
|
14
|
+
|
15
|
+
== LICENSE:
|
16
|
+
|
17
|
+
(The MIT License)
|
18
|
+
|
19
|
+
Copyright (c) 2008 Trek Glowacki
|
20
|
+
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
22
|
+
a copy of this software and associated documentation files (the
|
23
|
+
'Software'), to deal in the Software without restriction, including
|
24
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
25
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
26
|
+
permit persons to whom the Software is furnished to do so, subject to
|
27
|
+
the following conditions:
|
28
|
+
|
29
|
+
The above copyright notice and this permission notice shall be
|
30
|
+
included in all copies or substantial portions of the Software.
|
31
|
+
|
32
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
33
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
34
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
35
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
36
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
37
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
38
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'rtunesu/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Trek Glowacki'
|
4
|
+
EMAIL = "trek.glowacki@gmail.com"
|
5
|
+
DESCRIPTION = "A library for using Apple's iTunes U Webservices API"
|
6
|
+
GEM_NAME = 'rtunesu'
|
7
|
+
RUBYFORGE_PROJECT = 'rtunesu'
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
EXTRA_DEPENDENCIES = [
|
11
|
+
['ruby-hmac', '>= 0.3.1'],
|
12
|
+
['hpricot', '>= 0.6'],
|
13
|
+
['builder', '>= 2.0']
|
14
|
+
]
|
15
|
+
|
16
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
17
|
+
@config = nil
|
18
|
+
RUBYFORGE_USERNAME = "unknown"
|
19
|
+
def rubyforge_username
|
20
|
+
unless @config
|
21
|
+
begin
|
22
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
23
|
+
rescue
|
24
|
+
puts <<-EOS
|
25
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
26
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
27
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
28
|
+
EOS
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
REV = nil
|
37
|
+
# UNCOMMENT IF REQUIRED:
|
38
|
+
# REV = YAML.load(`svn info`)['Revision']
|
39
|
+
VERS = RTunesU::VERSION::STRING + (REV ? ".#{REV}" : "")
|
40
|
+
RDOC_OPTS = ['--quiet', '--title', 'rtunesu documentation',
|
41
|
+
"--opname", "index.html",
|
42
|
+
"--line-numbers",
|
43
|
+
"--main", "README",
|
44
|
+
"--inline-source"]
|
45
|
+
|
46
|
+
class Hoe
|
47
|
+
def extra_deps
|
48
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
49
|
+
@extra_deps
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Generate all the Rake tasks
|
54
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
55
|
+
$hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
56
|
+
p.developer(AUTHOR, EMAIL)
|
57
|
+
p.description = DESCRIPTION
|
58
|
+
p.summary = DESCRIPTION
|
59
|
+
p.url = HOMEPATH
|
60
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
61
|
+
p.test_globs = ["test/**/test_*.rb"]
|
62
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
63
|
+
|
64
|
+
# == Optional
|
65
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
66
|
+
#p.extra_deps = EXTRA_DEPENDENCIES
|
67
|
+
|
68
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
69
|
+
end
|
70
|
+
|
71
|
+
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
72
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
73
|
+
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
74
|
+
$hoe.rsync_args = '-av --delete --ignore-errors'
|
75
|
+
# $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
data/lib/multipart.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require "rubygems"
|
3
|
+
require "mime/types"
|
4
|
+
require "base64"
|
5
|
+
require 'cgi'
|
6
|
+
|
7
|
+
# Add multipart/form-data support to net/http
|
8
|
+
# From http://pivots.pivotallabs.com/users/damon/blog/articles/227-standup-04-27-07-testing-file-uploads
|
9
|
+
#
|
10
|
+
# == Usage
|
11
|
+
# File.open(File.expand_path('script/test.png'), 'r') do |file|
|
12
|
+
# http = Net::HTTP.new('localhost', 3000)
|
13
|
+
# begin
|
14
|
+
# http.start do |http|
|
15
|
+
# request = Net::HTTP::Post.new('/your/url/here')
|
16
|
+
# request.basic_auth 'lonely_user', 'really_long_password'
|
17
|
+
# request.multipart_params = {:file => file, :title => 'test.png'}
|
18
|
+
# response = http.request(request)
|
19
|
+
# response.value
|
20
|
+
# puts response.body
|
21
|
+
# end
|
22
|
+
# rescue Net::HTTPServerException => e
|
23
|
+
# p e
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
class Net::HTTP::Post
|
27
|
+
def multipart_params=(param_hash={})
|
28
|
+
boundary_token = [Array.new(8) {rand(256)}].join
|
29
|
+
self.content_type = "multipart/form-data; boundary=#{boundary_token}"
|
30
|
+
boundary_marker = "--#{boundary_token}\r\n"
|
31
|
+
self.body = param_hash.map { |param_name, param_value|
|
32
|
+
boundary_marker + case param_value
|
33
|
+
when File: file_to_multipart(param_name, param_value)
|
34
|
+
when String: text_to_multipart(param_name, param_value)
|
35
|
+
else ''
|
36
|
+
end
|
37
|
+
}.join('') + "--#{boundary_token}--\r\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
def file_to_multipart(key,file)
|
42
|
+
filename = File.basename(file.path)
|
43
|
+
mime_types = MIME::Types.of(filename)
|
44
|
+
mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
|
45
|
+
part = %Q{Content-Disposition: form-data; name="#{key}"; filename="#{filename}"\r\n}
|
46
|
+
part += "Content-Transfer-Encoding: binary\r\n"
|
47
|
+
part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}\r\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
def text_to_multipart(key,value)
|
51
|
+
"Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cgi'
|
3
|
+
require 'hmac'
|
4
|
+
require 'hmac-sha2'
|
5
|
+
require 'digest'
|
6
|
+
require 'net/https'
|
7
|
+
require 'uri'
|
8
|
+
require 'timeout'
|
9
|
+
|
10
|
+
module RTunesU
|
11
|
+
# Connection is a class for opening and using a connection to the iTunes U Webservices system. To open a connection to iTunes U, you first need to create a RTunesU::User object using the administrator data you received from Apple when they created your iTunes U site.
|
12
|
+
# === Creating a Connection
|
13
|
+
# include RTunesU
|
14
|
+
# # create a new admin user from our Institution's login information
|
15
|
+
# user = User.new(0, 'admin', 'Admin', 'admin@example.edu')
|
16
|
+
# # set the User credentials to the credentials Apple provider when we signed up
|
17
|
+
# user.credentials = ['Administrator@urn:mace:example.edu']
|
18
|
+
# # Create a new Connection object.
|
19
|
+
# connection = Connection.new(:user => user, :site => 'example.edu', :shared_secret => 'STRINGOFTHIRTYLETTERSORNUMBERS')
|
20
|
+
#
|
21
|
+
# === Using a Connection
|
22
|
+
# A Connection object is needed for operations that communicate with Apple's iTunes U Webservices. For example, calls to .save, .create, .update, and .delete on Entity objects take a Connection object as their only argument.
|
23
|
+
# To communicate with the iTunes U Service, a Connection object will generate proper authentication data, hash your request, and (if neccessary) send XML data to iTunes U.
|
24
|
+
# For more inforamtion about this processs see: http://deimos.apple.com/rsrc/doc/iTunesUAdministratorsGuide/IntegratingAuthenticationandAuthorizationServices/chapter_3_section_3.html
|
25
|
+
# === Scaling tips
|
26
|
+
# Because the you will likely only need a single unchanging Connection object for your application you may wish to initialize a single Connection object for the admin credentials at application start time and assign it to a constant. This is especially beneficial for long running applications like web applications.
|
27
|
+
class Connection
|
28
|
+
TIMEOUT = 240
|
29
|
+
|
30
|
+
attr_accessor :user, :options
|
31
|
+
|
32
|
+
def initialize(options = {})
|
33
|
+
self.user, self.options = options[:user], options
|
34
|
+
end
|
35
|
+
|
36
|
+
# iTunes U requires all request to include an authorization token that includes a User's credentials, indetifiying information, and the time of the request. This data is hashed against your institution's shared secret (provider by Apple with your iTunes U account information). Because tokens are valid only for 90 seconds they are generated for each request attempt.
|
37
|
+
def generate_authorization_token
|
38
|
+
# create the token that contains the necessary elements to authorize the user
|
39
|
+
# using a nested array because the alphabetical order must be maintained
|
40
|
+
token = [['credentials', self.user.to_credential_string,], ['identity', self.user.to_identity_string], ['time', Time.now.to_i.to_s]]
|
41
|
+
encoded_parms = token.collect {|pair| pair[1] = CGI.escape(pair[1]); pair.join('=')}.join('&')
|
42
|
+
|
43
|
+
digest = Digest::SHA2.new
|
44
|
+
digest.update(encoded_parms)
|
45
|
+
|
46
|
+
hmac = HMAC::SHA256.new(self.options[:shared_secret])
|
47
|
+
hmac.update(encoded_parms)
|
48
|
+
|
49
|
+
# add the hashed digital signature to the end of the query parameters
|
50
|
+
encoded_parms += "&signature=#{hmac.hexdigest}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def upload_url_for_location(location)
|
54
|
+
url_string = "#{API_URL}/GetUploadURL/#{self.options[:site]}.#{location.Handle}?#{self.generate_authorization_token}"
|
55
|
+
puts url_string
|
56
|
+
url = URI.parse(url_string)
|
57
|
+
http = Net::HTTP.new(url.host, url.port)
|
58
|
+
http.use_ssl = true
|
59
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
60
|
+
response = http.start {|http|
|
61
|
+
http.request(Net::HTTP::Get.new(url.path + '?' + url.query))
|
62
|
+
}
|
63
|
+
response.body
|
64
|
+
end
|
65
|
+
|
66
|
+
# The URL that receives all iTunes U webservices requests. This is different for each institution and inclues your site name provided by Apple.
|
67
|
+
def webservices_url
|
68
|
+
"#{API_URL}/ProcessWebServicesDocument/#{options[:site]}?#{self.generate_authorization_token}"
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
def browse_url
|
73
|
+
"#{BROWSE_URL}/#{options[:site]}?#{self.generate_authorization_token}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def show_tree
|
77
|
+
url = URI.parse("#{SHOW_TREE_URL}/#{options[:site]}?#{self.generate_authorization_token}")
|
78
|
+
http = Net::HTTP.new(url.host, url.port)
|
79
|
+
http.use_ssl = true
|
80
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
81
|
+
http.start {
|
82
|
+
request = Net::HTTP::Post.new(url.to_s)
|
83
|
+
response = http.request(request)
|
84
|
+
response.body
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sends a string of XML data to iTunes U's webservices url for processing. Returns the iTunes U response XML. Used by Entity objects to send generated XML to iTunes U.
|
89
|
+
def process(xml)
|
90
|
+
timeout(TIMEOUT) do
|
91
|
+
url = URI.parse(webservices_url)
|
92
|
+
http = Net::HTTP.new(url.host, url.port)
|
93
|
+
http.use_ssl = true
|
94
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
95
|
+
http.start {
|
96
|
+
request = Net::HTTP::Post.new(url.to_s)
|
97
|
+
request.body = xml
|
98
|
+
response = http.request(request)
|
99
|
+
response.body
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Uploads a file from the local system to iTunes U.
|
105
|
+
def upload_file(file, itunes_location)
|
106
|
+
IO::popen('-') do |c|
|
107
|
+
exec "curl -q -F 'file=@#{file.path}' '#{upload_url_for_location(itunes_location)}'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
module RTunesU
|
4
|
+
# Document is a class that generates the neccessary XML to interact with iTunes U. Documents are generated and sent when calling .save, .create, .update, and .delete on an specific Entity object. Classes in the Document:: namespace aren't intended for direct use.
|
5
|
+
# For example:
|
6
|
+
# c = Course.find(12345, itunes_connection_object)
|
7
|
+
# c.Name # "Exemple Course"
|
8
|
+
# c.Name = 'Example Course'
|
9
|
+
# c.save # genertes and sends a Document::Merge object with the Course data.
|
10
|
+
module Document
|
11
|
+
class Base
|
12
|
+
INDENT = 2
|
13
|
+
attr_accessor :builder, :source, :options, :xml
|
14
|
+
|
15
|
+
def initialize(source, options = {})
|
16
|
+
self.source, self.options = source, options
|
17
|
+
builder = Builder::XmlMarkup.new(:indent => INDENT)
|
18
|
+
builder.instruct!
|
19
|
+
builder.tag!('ITunesUDocument') {
|
20
|
+
builder.tag!('Version', RTunesU::API_VERSION)
|
21
|
+
self.xml = tag_action(builder)
|
22
|
+
}
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
# Implemented in each of the subclasses of Document::Base. Adds the particular action you would like to take (AddFoo, MergeFoo, DeleteFoo) to the Source class.
|
27
|
+
# For example, if the source Entity is of the type Track and you are creating a Document::Add the ITunesUDocument element will have a child element of <AddTrack>...</AddTrack>
|
28
|
+
# tag_action is called from inside Document::Base.new and is based the initializer's builder object so that proper nesting is maintained.
|
29
|
+
private
|
30
|
+
def tag_action(xml_builder)
|
31
|
+
return
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates an XML document that comforms to iTunes U's specification for adding an entity. This class is used internally by Entity classes when saving.
|
36
|
+
class Add < Base
|
37
|
+
private
|
38
|
+
def tag_action(xml_builder)
|
39
|
+
raise MissingParent if source.parent_handle.nil?
|
40
|
+
xml_builder.tag!("Add#{source.class_name}") {
|
41
|
+
xml_builder.tag!('ParentHandle', source.parent_handle)
|
42
|
+
# The existance of ParentPath is required for iTunesU documents, but can be blank
|
43
|
+
xml_builder.tag!('ParentPath', '')
|
44
|
+
source.to_xml(xml_builder)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Creates an XML document that comforms to iTunes U's specification for updating an entity. This class is used internally by Entity classes when saving.
|
50
|
+
class Merge < Base
|
51
|
+
private
|
52
|
+
def tag_action(xml_builder)
|
53
|
+
xml_builder.tag!("Merge#{source.class_name}") {
|
54
|
+
xml_builder.tag!("#{source.class_name}Handle", source.handle)
|
55
|
+
source.to_xml(xml_builder)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Creates an XML document that comforms to iTunes U's specification for deleting an entity. This class is used internally by Entity classes when saving.
|
61
|
+
class Delete < Base
|
62
|
+
private
|
63
|
+
def tag_action(xml_builder)
|
64
|
+
xml_builder.tag!("Delete#{source.class_name}") {
|
65
|
+
xml_builder.tag!("#{source.class_name}Handle", source.handle)
|
66
|
+
xml_builder.tag!("#{source.class_name}Path", '') unless source.class_name == 'Track'
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Shows the hierarchy tree for a portion of your iTunes U site. If the source object has no handle, the tree for your entire site is shown.
|
72
|
+
# ShowTree.new can take an option options hash. The possible values for this hash are
|
73
|
+
# :key_group. They iTunes U 'KeyGroup' that defines the amount of data returned from the ShowTree action. Possible values are 'minimal','most','maximal'.
|
74
|
+
class ShowTree < Base
|
75
|
+
private
|
76
|
+
def tag_action(xml_builder)
|
77
|
+
xml_builder.tag!('ShowTree') {
|
78
|
+
xml_builder.tag!('Handle', self.source.handle) if self.source.handle
|
79
|
+
xml_builder.tag!('KeyGroup', options[:key_group] || 'most')
|
80
|
+
}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RTunesU
|
2
|
+
# A Division in iTunes U is a seperate nested area of your iTunes U Site. It is different than a Section which is expressed in iTunes a a seperate area on a single page.
|
3
|
+
# == Attributes
|
4
|
+
# Handle
|
5
|
+
# Name
|
6
|
+
# ShortName
|
7
|
+
# AggregateFileSize (read only)
|
8
|
+
# Identifier
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# == Nested Entities
|
12
|
+
# Permission
|
13
|
+
# Section
|
14
|
+
class Division < Entity
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RTunesU
|
2
|
+
# A Section in iTunes U. A Section is expressed in the iTunes interface as a visually seperate area on a single page. This is different than a Division which is a seperate nested area of iTunes U.
|
3
|
+
# == Attributes
|
4
|
+
# Handle
|
5
|
+
# Name
|
6
|
+
# AllowSubscription
|
7
|
+
# AggregateFileSize (read only)
|
8
|
+
#
|
9
|
+
# == Nested Entities
|
10
|
+
# Permission
|
11
|
+
# Course
|
12
|
+
# Division
|
13
|
+
class Section < Entity
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RTunesU
|
2
|
+
# A Track in iTunes U.
|
3
|
+
# == Attributes
|
4
|
+
# == Nested Entities
|
5
|
+
class Track < Entity
|
6
|
+
# Tracks can only be found from within their Course. There is currently no way to find a Track separete from its Course.
|
7
|
+
def self.find(handle, course_handle, connection)
|
8
|
+
entity = self.new(:handle => handle)
|
9
|
+
entity.source_xml = Course.find(course_handle, connection).source_xml.at("Handle[text()=#{entity.handle}]..")
|
10
|
+
entity
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|