scorm_engine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Rakefile +13 -0
  4. data/lib/scorm_engine.rb +13 -0
  5. data/lib/scorm_engine/api/endpoints.rb +50 -0
  6. data/lib/scorm_engine/api/endpoints/about.rb +59 -0
  7. data/lib/scorm_engine/api/endpoints/courses.rb +136 -0
  8. data/lib/scorm_engine/api/endpoints/courses/configuration.rb +146 -0
  9. data/lib/scorm_engine/api/endpoints/courses/import.rb +83 -0
  10. data/lib/scorm_engine/api/endpoints/ping.rb +20 -0
  11. data/lib/scorm_engine/api/endpoints/registrations.rb +321 -0
  12. data/lib/scorm_engine/api/endpoints/registrations/configuration.rb +146 -0
  13. data/lib/scorm_engine/api/endpoints/registrations/launch_history.rb +47 -0
  14. data/lib/scorm_engine/client.rb +17 -0
  15. data/lib/scorm_engine/configuration.rb +43 -0
  16. data/lib/scorm_engine/faraday/connection.rb +35 -0
  17. data/lib/scorm_engine/faraday/request.rb +54 -0
  18. data/lib/scorm_engine/models.rb +9 -0
  19. data/lib/scorm_engine/models/course.rb +66 -0
  20. data/lib/scorm_engine/models/course_configuration.rb +37 -0
  21. data/lib/scorm_engine/models/course_import.rb +42 -0
  22. data/lib/scorm_engine/models/learner.rb +24 -0
  23. data/lib/scorm_engine/models/registration.rb +82 -0
  24. data/lib/scorm_engine/models/registration_activity_detail.rb +37 -0
  25. data/lib/scorm_engine/models/registration_configuration.rb +37 -0
  26. data/lib/scorm_engine/models/registration_launch_history.rb +92 -0
  27. data/lib/scorm_engine/models/registration_runtime_interaction.rb +52 -0
  28. data/lib/scorm_engine/response.rb +26 -0
  29. data/lib/scorm_engine/utils.rb +13 -0
  30. data/lib/scorm_engine/version.rb +3 -0
  31. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about/is_successful.yml +38 -0
  32. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about/knows_the_platform.yml +38 -0
  33. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about/knows_the_version.yml +38 -0
  34. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about_user_count/accepts_before_option.yml +38 -0
  35. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about_user_count/accepts_since_option.yml +38 -0
  36. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about_user_count/is_successful.yml +38 -0
  37. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about_user_count/tracks_combined_counts.yml +38 -0
  38. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_About/_get_about_user_count/tracks_per_tenantcounts.yml +38 -0
  39. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_delete_course/fails_when_id_is_invalid.yml +38 -0
  40. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_delete_course/works.yml +32 -0
  41. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_course_detail/is_successful.yml +41 -0
  42. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_course_detail/results/sucessfully_creates_the_Course_attributes.yml +41 -0
  43. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_course_preview/fails_when_id_is_invalid.yml +38 -0
  44. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_course_preview/is_successful.yml +38 -0
  45. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_course_preview/results/returns_a_URL_string.yml +38 -0
  46. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_course_id_option/fetches_a_single_course_but_perhaps_multiple_versions.yml +39 -0
  47. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_course_id_option/returns_404_when_ID_is_invalid.yml +38 -0
  48. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_more_option_pagination_/returns_all_the_courses.yml +89 -0
  49. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_more_option_pagination_/returns_the_more_key_in_the_raw_response.yml +48 -0
  50. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_since_option/fails_when_passed_an_invalid_value.yml +37 -0
  51. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/_since_option/works.yml +43 -0
  52. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/is_successful.yml +43 -0
  53. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/results/is_an_enumerator_of_Course_models.yml +43 -0
  54. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses/_get_courses/results/sucessfully_creates_the_Course_attributes.yml +43 -0
  55. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration/fails_when_id_is_invalid.yml +38 -0
  56. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration/is_successful.yml +38 -0
  57. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration/results/makes_settings_available_as_key/value_pairs.yml +38 -0
  58. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration_setting/fails_when_course_id_is_invalid.yml +38 -0
  59. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration_setting/fails_when_setting_id_is_invalid.yml +36 -0
  60. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration_setting/is_successful.yml +65 -0
  61. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_get_course_configuration_setting/results/returns_the_value_as_a_string.yml +65 -0
  62. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_post_course_configuration/fails_when_id_is_invalid.yml +38 -0
  63. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_post_course_configuration/fails_when_settings_are_invalid.yml +36 -0
  64. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_post_course_configuration/is_successful.yml +32 -0
  65. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_post_course_configuration/persists_the_settings.yml +131 -0
  66. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_put_course_configuration_setting/fails_when_course_id_is_invalid.yml +38 -0
  67. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_put_course_configuration_setting/fails_when_setting_id_is_invalid.yml +36 -0
  68. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_put_course_configuration_setting/is_successful.yml +65 -0
  69. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Configuration/_put_course_configuration_setting/results/persists_the_changes.yml +98 -0
  70. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Import/_get_course_import/successful_imports/works.yml +147 -0
  71. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Import/_get_course_import/unsuccessful_imports/fails_to_import_given_an_invalid_url.yml +326 -0
  72. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Import/_post_course_import/successful_imports/works.yml +38 -0
  73. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Courses_Import/_post_course_import/unsuccessful_imports/fails_to_import_a_previously_existing_course.yml +36 -0
  74. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Ping/_get_ping/is_successful.yml +38 -0
  75. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Ping/_get_ping/reports_the_api_is_up.yml +38 -0
  76. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Ping/_get_ping/with_invalid_password/is_unsuccessful.yml +41 -0
  77. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Ping/_get_ping/with_invalid_password/returns_status_403.yml +41 -0
  78. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_delete_registration/is_failure_when_registration_does_not_exist.yml +38 -0
  79. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_delete_registration/is_successful_when_registration_exists.yml +32 -0
  80. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_exists/is_false_when_registration_does_not_exist.yml +38 -0
  81. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_exists/is_true_when_registration_exists.yml +36 -0
  82. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_instances/includes_results_we_expect.yml +39 -0
  83. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_instances/is_successful.yml +39 -0
  84. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_instances/returns_an_array_of_registrations.yml +39 -0
  85. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_launch_link/fails_when_id_is_invalid.yml +38 -0
  86. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_launch_link/is_successful.yml +38 -0
  87. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_launch_link/results/returns_a_URL_string.yml +38 -0
  88. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_progress/detail/does_not_return_activity_details_by_default.yml +39 -0
  89. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_progress/detail/returns_activity_details_if_requested.yml +41 -0
  90. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_progress/fails_when_registration_does_not_exist.yml +38 -0
  91. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registration_progress/returns_a_registration_when_it_exists.yml +39 -0
  92. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/filtering_by_course_id/excludes_results.yml +38 -0
  93. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/filtering_by_course_id/includes_results.yml +40 -0
  94. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/filtering_by_learner_id/excludes_results.yml +38 -0
  95. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/filtering_by_learner_id/includes_results.yml +39 -0
  96. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/includes_results_we_expect.yml +40 -0
  97. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/is_successful.yml +40 -0
  98. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_get_registrations/returns_an_array_of_registrations.yml +40 -0
  99. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_post_registration/fails_if_course_id_is_invalid.yml +36 -0
  100. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_post_registration/fails_if_registration_id_already_exists.yml +36 -0
  101. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations/_post_registration/is_successful.yml +61 -0
  102. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration/fails_when_id_is_invalid.yml +38 -0
  103. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration/is_successful.yml +38 -0
  104. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration/results/makes_settings_available_as_key/value_pairs.yml +38 -0
  105. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration_setting/fails_when_registration_id_is_invalid.yml +38 -0
  106. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration_setting/fails_when_setting_id_is_invalid.yml +36 -0
  107. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration_setting/is_successful.yml +65 -0
  108. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_get_registration_configuration_setting/results/returns_the_value_as_a_string.yml +65 -0
  109. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_post_registration_configuration/fails_when_id_is_invalid.yml +38 -0
  110. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_post_registration_configuration/fails_when_settings_are_invalid.yml +36 -0
  111. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_post_registration_configuration/is_successful.yml +32 -0
  112. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_post_registration_configuration/persists_the_settings.yml +131 -0
  113. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_put_registration_configuration_setting/fails_when_registration_id_is_invalid.yml +38 -0
  114. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_put_registration_configuration_setting/fails_when_setting_id_is_invalid.yml +36 -0
  115. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_put_registration_configuration_setting/is_successful.yml +65 -0
  116. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_Configuration/_put_registration_configuration_setting/results/persists_the_changes.yml +98 -0
  117. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_LaunchHistory/_get_registration_launch_history/fails_when_registration_does_not_exist.yml +38 -0
  118. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_LaunchHistory/_get_registration_launch_history/is_successful.yml +54 -0
  119. data/spec/fixtures/vcr/ScormEngine_Api_Endpoints_Registrations_LaunchHistory/_get_registration_launch_history/returns_an_array_of_registration_launch_histories.yml +54 -0
  120. data/spec/fixtures/zip/Non-working SCORM.zip +0 -0
  121. data/spec/fixtures/zip/RuntimeBasicCalls_SCORM20043rdEdition.zip +0 -0
  122. data/spec/scorm_engine/api/endpoints/about_spec.rb +59 -0
  123. data/spec/scorm_engine/api/endpoints/courses/configuration_spec.rb +143 -0
  124. data/spec/scorm_engine/api/endpoints/courses/import_spec.rb +92 -0
  125. data/spec/scorm_engine/api/endpoints/courses_spec.rb +155 -0
  126. data/spec/scorm_engine/api/endpoints/ping_spec.rb +27 -0
  127. data/spec/scorm_engine/api/endpoints/registrations/configuration_spec.rb +154 -0
  128. data/spec/scorm_engine/api/endpoints/registrations/launch_history_spec.rb +46 -0
  129. data/spec/scorm_engine/api/endpoints/registrations_spec.rb +201 -0
  130. data/spec/scorm_engine/configuration_spec.rb +29 -0
  131. data/spec/scorm_engine/models/course_configuration_spec.rb +16 -0
  132. data/spec/scorm_engine/models/course_import_spec.rb +86 -0
  133. data/spec/scorm_engine/models/course_spec.rb +92 -0
  134. data/spec/scorm_engine/models/learner_spec.rb +27 -0
  135. data/spec/scorm_engine/models/registration_activity_detail_spec.rb +101 -0
  136. data/spec/scorm_engine/models/registration_launch_history_spec.rb +86 -0
  137. data/spec/scorm_engine/models/registration_runtime_interaction_spec.rb +91 -0
  138. data/spec/scorm_engine/models/registration_spec.rb +82 -0
  139. data/spec/scorm_engine/utils_spec.rb +15 -0
  140. data/spec/scorm_engine/version_spec.rb +5 -0
  141. data/spec/scorm_engine_spec.rb +2 -0
  142. data/spec/spec_helper.rb +47 -0
  143. data/spec/support/scorm_engine.rb +72 -0
  144. data/spec/support/scorm_engine_client.rb +6 -0
  145. data/spec/support/scorm_engine_configuration.rb +7 -0
  146. data/spec/support/vcr.rb +53 -0
  147. metadata +329 -0
@@ -0,0 +1,47 @@
1
+ module ScormEngine
2
+ module Api
3
+ module Endpoints
4
+ module Registrations
5
+ module LaunchHistory
6
+ #
7
+ # Get launch history data associated with this registration
8
+ #
9
+ # @see http://rustici-docs.s3.amazonaws.com/engine/2017.1.x/api.html#tenant__registrations__registrationId__launchHistory_get
10
+ #
11
+ # @param [Hash] options
12
+ #
13
+ # @option options [String] :registration_id
14
+ # ID for the registration.
15
+ #
16
+ # @option options [String] :instance ()
17
+ # The instance of this registration to use. If not provided, the
18
+ # latest instance will be used.
19
+ #
20
+ # @option options [Boolean] :include_history_log (false)
21
+ # Whether to include the history log in the launch history. The
22
+ # history log is a blob of XML that shows all of the SCORM-related
23
+ # calls inside the course. Depending on the course itself, these logs
24
+ # can get very large if a lot of calls are being made.
25
+ #
26
+ # @return [Array<ScormEngine::Models::RegistrationLaunchHistory>]
27
+ #
28
+ def get_registration_launch_history(options = {})
29
+ require_options(options, :registration_id)
30
+
31
+ options = options.dup
32
+ registration_id = options.delete(:registration_id)
33
+ options[:includeHistoryLog] = !!options.delete(:include_history_log)
34
+
35
+ response = get("registrations/#{registration_id}/launchHistory", options)
36
+
37
+ result = response.success? && response.body["launchHistory"].map do |history|
38
+ ScormEngine::Models::RegistrationLaunchHistory.new_from_api(history)
39
+ end
40
+
41
+ Response.new(raw_response: response, result: result)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "faraday/connection"
2
+ require_relative "faraday/request"
3
+
4
+ module ScormEngine
5
+ class Client
6
+
7
+ include Faraday::Connection
8
+ include Faraday::Request
9
+ include Api::Endpoints
10
+
11
+ attr_reader :tenant
12
+
13
+ def initialize(tenant:)
14
+ @tenant = tenant
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ require "logger"
2
+
3
+ module ScormEngine
4
+ def self.configuration
5
+ @configuration ||= Configuration.new
6
+ end
7
+
8
+ def self.configure
9
+ yield(configuration)
10
+ end
11
+
12
+ class Configuration
13
+ # http://rustici-docs.s3.amazonaws.com/engine/2017.1.x/api.html
14
+ attr_accessor :host, :path_prefix
15
+
16
+ # http://rustici-docs.s3.amazonaws.com/engine/2017.1.x/Architecture-API.html#api-authentication
17
+ attr_accessor :username, :password
18
+
19
+ # defaults to /dev/null
20
+ # https://github.com/lostisland/faraday/blob/5f1687abbe9eb1c96284b31e303e80f1a22acd09/lib/faraday/response/logger.rb#L7
21
+ attr_accessor :logger, :log_options
22
+
23
+ def initialize
24
+ reset
25
+ end
26
+
27
+ def reset
28
+ @host = ENV["SCORM_ENGINE_HOST"]
29
+ @path_prefix = "/ScormEngineInterface/api/v1/"
30
+
31
+ @username = ENV["SCORM_ENGINE_USERNAME"]
32
+ @password = ENV["SCORM_ENGINE_PASSWORD"]
33
+
34
+ @logger = ::Logger.new(ENV.fetch("SCORM_ENGINE_LOGFILE", "/dev/null"))
35
+
36
+ @log_options = begin
37
+ JSON.parse(ENV.fetch("SCORM_ENGINE_LOG_OPTIONS"))
38
+ rescue KeyError, JSON::ParserError
39
+ { headers: false, bodies: false }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ require "faraday"
2
+ require "faraday_middleware"
3
+
4
+ module ScormEngine
5
+ module Faraday
6
+ module Connection
7
+ private
8
+
9
+ def connection
10
+ @connection ||= ::Faraday.new(url: base_uri.to_s) do |faraday|
11
+ faraday.headers["Content-Type"] = "application/json"
12
+ faraday.headers["User-Agent"] = "ScormEngine Ruby Gem #{ScormEngine::VERSION}"
13
+
14
+ faraday.basic_auth(ScormEngine.configuration.username, ScormEngine.configuration.password)
15
+
16
+ faraday.request :multipart
17
+ faraday.request :json
18
+
19
+ faraday.response :json, content_type: /\bjson$/
20
+ faraday.response :logger, ScormEngine.configuration.logger, ScormEngine.configuration.log_options
21
+
22
+ faraday.adapter ::Faraday.default_adapter
23
+ end
24
+ end
25
+
26
+ def base_uri
27
+ uri = URI("")
28
+ uri.scheme = "https" # TODO: Make configurable
29
+ uri.host = ScormEngine.configuration.host
30
+ uri.path = ScormEngine.configuration.path_prefix
31
+ uri
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,54 @@
1
+ module ScormEngine
2
+ module Faraday
3
+ module Request
4
+ def get(path, options = {})
5
+ request(:get, path, options)
6
+ end
7
+
8
+ def post(path, options = {}, body = nil)
9
+ request(:post, path, options, body)
10
+ end
11
+
12
+ def put(path, options = {}, body = nil)
13
+ request(:put, path, options, body)
14
+ end
15
+
16
+ def delete(path, options = {})
17
+ request(:delete, path, options)
18
+ end
19
+
20
+ private
21
+
22
+ def request(method, path, options, body = nil)
23
+ # "more" pagination urls are fully qualified
24
+ path = "#{tenant}/#{path}" unless path =~ %r{\Ahttps?://}
25
+
26
+ options = coerce_options(options)
27
+
28
+ connection.send(method) do |request|
29
+ case method
30
+ when :get, :delete
31
+ request.url(path, options)
32
+ when :post, :put
33
+ if body.nil?
34
+ body = options.dup
35
+ options = {}
36
+ end
37
+ request.url(path, options)
38
+ request.body = body unless body.empty?
39
+ end
40
+ end
41
+ end
42
+
43
+ def coerce_options(options = {})
44
+ options.dup.each do |k, v|
45
+ case k
46
+ when :before, :since
47
+ options[k] = v.iso8601 if v.respond_to?(:iso8601)
48
+ end
49
+ end
50
+ options
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "models/course"
2
+ require_relative "models/course_configuration"
3
+ require_relative "models/course_import"
4
+ require_relative "models/learner"
5
+ require_relative "models/registration"
6
+ require_relative "models/registration_activity_detail"
7
+ require_relative "models/registration_configuration"
8
+ require_relative "models/registration_launch_history"
9
+ require_relative "models/registration_runtime_interaction"
@@ -0,0 +1,66 @@
1
+ require "time"
2
+
3
+ module ScormEngine
4
+ module Models
5
+ class Course
6
+ attr_accessor :options
7
+ private :options
8
+
9
+ # TODO: Not sure we want this to be settable. Will depend on how we go
10
+ # about creating/updating records. For now it makes it easier to create
11
+ # instances from API options hash.
12
+ attr_accessor :id, :version, :title, :registration_count, :updated, :description,
13
+ :scaled_passing_score
14
+
15
+ def self.new_from_api(options = {})
16
+ this = new
17
+
18
+ this.options = options.dup
19
+ this.id = options["id"]
20
+ this.version = options["version"]
21
+ this.title = get_title_from_api(options)
22
+ this.registration_count = options["registrationCount"]
23
+ this.updated = Time.parse(options["updated"]) if options.key?("updated")
24
+ this.description = options.fetch("metadata", {})["description"]
25
+ this.scaled_passing_score = get_scaled_passing_score_from_api(options)
26
+
27
+ this
28
+ end
29
+
30
+ #
31
+ # Extract and sanitize the title from the API options.
32
+ #
33
+ # Special consideration is given to two commonly found, but useless
34
+ # titles which if found will result in a blank title.
35
+ #
36
+ # @param [Hash] options
37
+ # The API options hash
38
+ #
39
+ # @return [String]
40
+ #
41
+ def self.get_title_from_api(options = {})
42
+ title = ScormEngine::Utils.sanitized_text(options["title"])
43
+ title = "" if ["Title", "Captivate E-Learning Course"].include?(title)
44
+ title
45
+ end
46
+
47
+ #
48
+ # Extract and normalize the scaled passing score from the API options.
49
+ #
50
+ # @param [Hash] options
51
+ # The API options hash
52
+ #
53
+ # @return [Integer]
54
+ # An integer between 0 and 100 or nil if undefined.
55
+ #
56
+ def self.get_scaled_passing_score_from_api(options = {})
57
+ first_child = options.fetch("rootActivity", {}).fetch("children", [{}]).first
58
+ score = first_child.is_a?(Hash) ? first_child["scaledPassingScore"] : nil
59
+ return if score.nil?
60
+ score = score.to_f
61
+ score *= 100 if score <= 1.0
62
+ score.to_i
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,37 @@
1
+ module ScormEngine
2
+ module Models
3
+ class CourseConfiguration
4
+ attr_accessor :options
5
+ private :options
6
+
7
+ # TODO: Not sure we want this to be settable. Will depend on how we go
8
+ # about creating/updating records. For now it makes it easier to create
9
+ # instances from API options hash.
10
+ attr_accessor :settings
11
+
12
+ def self.new_from_api(options = {})
13
+ this = new
14
+
15
+ this.options = options.dup
16
+ this.settings = get_settings_from_api(options)
17
+ this
18
+ end
19
+
20
+ #
21
+ # Extract and normalize the settings from the API options.
22
+ #
23
+ # @param [Hash] options
24
+ # The API options hash
25
+ #
26
+ # @return [Hash]
27
+ # A hash of key/value pairs.
28
+ #
29
+ def self.get_settings_from_api(options = {})
30
+ options["configurationItems"].reduce({}) do |m, o|
31
+ m[o["id"]] = o["value"]
32
+ m
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ module ScormEngine
2
+ module Models
3
+ class CourseImport
4
+ attr_accessor :options
5
+ private :options
6
+
7
+ # TODO: Not sure we want this to be settable. Will depend on how we go
8
+ # about creating/updating records. For now it makes it easier to create
9
+ # instances from API options hash.
10
+ attr_accessor :id, :status, :parser_warnings, :course
11
+
12
+ def self.new_from_api(options = {})
13
+ this = new
14
+ this.options = options.dup
15
+
16
+ if options.key?("importResult")
17
+ this.id = options["result"]
18
+ this.status = options.fetch("importResult", {})["status"]
19
+ this.parser_warnings = options.fetch("importResult", {})["parserWarnings"]
20
+ else
21
+ this.id = options["jobId"]
22
+ this.status = options["status"]
23
+ this.course = Course.new_from_api(options["course"]) if options.key?("course") # unavailable in error states
24
+ end
25
+
26
+ this
27
+ end
28
+
29
+ def running?
30
+ status == "RUNNING"
31
+ end
32
+
33
+ def error?
34
+ status == "ERROR"
35
+ end
36
+
37
+ def complete?
38
+ status == "COMPLETE"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ module ScormEngine
2
+ module Models
3
+ class Learner
4
+ attr_accessor :options
5
+ private :options
6
+
7
+ # TODO: Not sure we want this to be settable. Will depend on how we go
8
+ # about creating/updating records. For now it makes it easier to create
9
+ # instances from API options hash.
10
+ attr_accessor :id, :first_name, :last_name
11
+
12
+ def self.new_from_api(options = {})
13
+ this = new
14
+
15
+ this.options = options.dup
16
+ this.id = options["id"]
17
+ this.first_name = options["firstName"]
18
+ this.last_name = options["lastName"]
19
+
20
+ this
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,82 @@
1
+ #
2
+ # TODO: Incorporate all the activity props from:
3
+ # http://rustici-docs.s3.amazonaws.com/engine/2017.1.x/api.html#tenant__registrations__registrationId__progress_get
4
+ # http://rustici-docs.s3.amazonaws.com/engine/2017.1.x/api.html#tenant__registrations__registrationId__progress_detail_get
5
+ #
6
+ # TODO: Confirmed they are the only values. Integrate them into the model.
7
+ # registrationCompletion: ["COMPLETED", "INCOMPLETE", "UNKNOWN"]
8
+ # registrationSuccess: ["Unknown", "Passed", "Failed"]
9
+ #
10
+ module ScormEngine
11
+ module Models
12
+ class Registration
13
+ attr_accessor :options
14
+ private :options
15
+
16
+ # TODO: Not sure we want this to be settable. Will depend on how we go
17
+ # about creating/updating records. For now it makes it easier to create
18
+ # instances from API options hash.
19
+ attr_accessor :id, :instance, :updated, :registration_completion, :registration_success,
20
+ :total_seconds_tracked, :score, :course, :learner, :activity_details,
21
+ :first_access_date, :last_access_date, :completed_date, :created_date,
22
+ :registration_completion_amount
23
+
24
+ def self.new_from_api(options = {})
25
+ this = new
26
+
27
+ this.options = options.dup
28
+ this.id = options["id"]
29
+ this.instance = options["instance"]
30
+ this.updated = Time.parse(options["updated"]) if options.key?("updated")
31
+ this.registration_completion = options["registrationCompletion"]
32
+ this.registration_success = options["registrationSuccess"]
33
+ this.total_seconds_tracked = options["totalSecondsTracked"]
34
+ this.first_access_date = Time.parse(options["firstAccessDate"]) if options.key?("firstAccessDate")
35
+ this.last_access_date = Time.parse(options["lastAccessDate"]) if options.key?("lastAccessDate")
36
+ this.created_date = Time.parse(options["createdDate"]) if options.key?("createdDate")
37
+ this.updated = Time.parse(options["updated"]) if options.key?("updated")
38
+ this.registration_completion_amount = options["registrationCompletionAmount"].to_f # Sometimes it returns "NaN"
39
+
40
+ this.score = get_score_from_api(options)
41
+ this.completed_date = get_completed_at_from_api(options)
42
+
43
+ this.activity_details = RegistrationActivityDetail.new_from_api(options["activityDetails"]) if options.key?("activityDetails")
44
+ this.course = Course.new_from_api(options["course"]) if options.key?("course")
45
+ this.learner = Learner.new_from_api(options["learner"]) if options.key?("learner")
46
+
47
+ this
48
+ end
49
+
50
+ #
51
+ # Extract and normalize the scaled passing score from the API options.
52
+ #
53
+ # @param [Hash] options
54
+ # The API options hash
55
+ #
56
+ # @return [Float]
57
+ # A float between 0 and 100 or nil if undefined.
58
+ #
59
+ def self.get_score_from_api(options = {})
60
+ score = options.fetch("score", {})["scaled"]
61
+ return if score.nil?
62
+ score.to_f
63
+ end
64
+
65
+ #
66
+ # Extract and normalize the completed date from the API options.
67
+ #
68
+ # @param [Hash] options
69
+ # The API options hash
70
+ #
71
+ # @return [Time]
72
+ # a date/time or nil if undefined.
73
+ #
74
+ def self.get_completed_at_from_api(options = {})
75
+ completed_date = options["completedDate"]
76
+ completed_date ||= options.fetch("score", {})["completedDate"]
77
+ return if completed_date.nil?
78
+ Time.parse(completed_date)
79
+ end
80
+ end
81
+ end
82
+ end