rtunesu 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/History.txt +4 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +77 -0
  4. data/README.txt +38 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +75 -0
  7. data/config/requirements.rb +15 -0
  8. data/lib/multipart.rb +53 -0
  9. data/lib/rtunesu/connection.rb +111 -0
  10. data/lib/rtunesu/document.rb +84 -0
  11. data/lib/rtunesu/entities/course.rb +8 -0
  12. data/lib/rtunesu/entities/division.rb +16 -0
  13. data/lib/rtunesu/entities/group.rb +8 -0
  14. data/lib/rtunesu/entities/permission.rb +7 -0
  15. data/lib/rtunesu/entities/section.rb +15 -0
  16. data/lib/rtunesu/entities/site.rb +7 -0
  17. data/lib/rtunesu/entities/theme.rb +4 -0
  18. data/lib/rtunesu/entities/track.rb +13 -0
  19. data/lib/rtunesu/entity.rb +154 -0
  20. data/lib/rtunesu/user.rb +26 -0
  21. data/lib/rtunesu/version.rb +9 -0
  22. data/lib/rtunesu.rb +25 -0
  23. data/script/console +10 -0
  24. data/script/destroy +14 -0
  25. data/script/generate +14 -0
  26. data/script/txt2html +82 -0
  27. data/setup.rb +1585 -0
  28. data/spec/connection_spec.rb +53 -0
  29. data/spec/document_spec.rb +16 -0
  30. data/spec/documents/add_spec.rb +41 -0
  31. data/spec/documents/delete_spec.rb +30 -0
  32. data/spec/documents/merge_spec.rb +30 -0
  33. data/spec/documents/show_tree_spec.rb +16 -0
  34. data/spec/entities/course_spec.rb +47 -0
  35. data/spec/entities/division_spec.rb +8 -0
  36. data/spec/entities/group_spec.rb +8 -0
  37. data/spec/entities/permission_spec.rb +8 -0
  38. data/spec/entities/section_spec.rb +8 -0
  39. data/spec/entities/site_spec.rb +8 -0
  40. data/spec/entities/track_spec.rb +8 -0
  41. data/spec/entity_spec.rb +108 -0
  42. data/spec/fixtures/add_course.xml +26 -0
  43. data/spec/fixtures/add_division.xml +26 -0
  44. data/spec/fixtures/add_group.xml +27 -0
  45. data/spec/fixtures/add_permission.xml +12 -0
  46. data/spec/fixtures/add_section.xml +34 -0
  47. data/spec/fixtures/add_track.xml +19 -0
  48. data/spec/fixtures/delete_course.xml +8 -0
  49. data/spec/fixtures/delete_division.xml +8 -0
  50. data/spec/fixtures/delete_group.xml +8 -0
  51. data/spec/fixtures/delete_permission.xml +9 -0
  52. data/spec/fixtures/delete_section.xml +8 -0
  53. data/spec/fixtures/delete_track.xml +7 -0
  54. data/spec/fixtures/merge_course.xml +38 -0
  55. data/spec/fixtures/merge_division.xml +47 -0
  56. data/spec/fixtures/merge_group.xml +29 -0
  57. data/spec/fixtures/merge_permission.xml +12 -0
  58. data/spec/fixtures/merge_section.xml +36 -0
  59. data/spec/fixtures/merge_site.xml +31 -0
  60. data/spec/fixtures/merge_track.xml +18 -0
  61. data/spec/fixtures/requests/add_coures_request.xml +0 -0
  62. data/spec/fixtures/responses/generic_entity_response.xml +17 -0
  63. data/spec/fixtures/responses/show_tree_course.xml +676 -0
  64. data/spec/fixtures/show_tree.xml +273 -0
  65. data/spec/fixtures/update_group.xml +7 -0
  66. data/spec/spec.opts +1 -0
  67. data/spec/spec_helper.rb +10 -0
  68. data/spec/user_spec.rb +18 -0
  69. data/tasks/deployment.rake +34 -0
  70. data/tasks/environment.rake +7 -0
  71. data/tasks/rspec.rake +21 -0
  72. data/tasks/website.rake +17 -0
  73. data/website/index.html +141 -0
  74. data/website/index.txt +83 -0
  75. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  76. data/website/stylesheets/screen.css +138 -0
  77. data/website/template.html.erb +48 -0
  78. metadata +144 -0
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-06-27
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
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
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
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,8 @@
1
+ module RTunesU
2
+ # A Course in iTunes U.
3
+ # == Attributes
4
+ # == Nested Entities
5
+
6
+ class Course < Entity
7
+ end
8
+ 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,8 @@
1
+ module RTunesU
2
+ # A Group in iTunes U. A Group is expressed as a tab in the iTunes interface.
3
+ # == Attributes
4
+ # == Nested Entities
5
+ # Track
6
+ class Group < Entity
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module RTunesU
2
+ # A Permission in iTunes U.
3
+ # == Attributes
4
+ # == Nested Entities
5
+ class Permission < Entity
6
+ end
7
+ 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,7 @@
1
+ module RTunesU
2
+ # A Site in iTunes U.
3
+ # == Attributes
4
+ # == Nested Entities
5
+ class Site
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ module RTunesU
2
+ class Theme < Entity
3
+ end
4
+ 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