growthtribe_xapi 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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +28 -0
  3. data/CHANGELOG.md +2 -0
  4. data/CONTRIBUTING.md +7 -0
  5. data/Gemfile +4 -0
  6. data/Gemfile.lock +78 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +299 -0
  9. data/Rakefile +12 -0
  10. data/bin/rspec +29 -0
  11. data/lib/growthtribe_xapi.rb +2 -0
  12. data/lib/xapi.rb +224 -0
  13. data/lib/xapi/about.rb +15 -0
  14. data/lib/xapi/activity.rb +37 -0
  15. data/lib/xapi/activity_definition.rb +131 -0
  16. data/lib/xapi/agent.rb +44 -0
  17. data/lib/xapi/agent_account.rb +33 -0
  18. data/lib/xapi/attachment.rb +64 -0
  19. data/lib/xapi/context.rb +54 -0
  20. data/lib/xapi/context_activities.rb +102 -0
  21. data/lib/xapi/documents/activity_profile_document.rb +15 -0
  22. data/lib/xapi/documents/agent_profile_document.rb +15 -0
  23. data/lib/xapi/documents/document.rb +20 -0
  24. data/lib/xapi/documents/state_document.rb +15 -0
  25. data/lib/xapi/enum.rb +42 -0
  26. data/lib/xapi/errors.rb +9 -0
  27. data/lib/xapi/group.rb +37 -0
  28. data/lib/xapi/interaction_component.rb +32 -0
  29. data/lib/xapi/interaction_type.rb +58 -0
  30. data/lib/xapi/lrs_response.rb +14 -0
  31. data/lib/xapi/query_result_format.rb +6 -0
  32. data/lib/xapi/remote_lrs.rb +416 -0
  33. data/lib/xapi/result.rb +46 -0
  34. data/lib/xapi/score.rb +39 -0
  35. data/lib/xapi/statement.rb +53 -0
  36. data/lib/xapi/statement_ref.rb +31 -0
  37. data/lib/xapi/statements/statements_base.rb +70 -0
  38. data/lib/xapi/statements_query.rb +42 -0
  39. data/lib/xapi/statements_query_v095.rb +42 -0
  40. data/lib/xapi/statements_result.rb +17 -0
  41. data/lib/xapi/sub_statement.rb +19 -0
  42. data/lib/xapi/tcapi_version.rb +27 -0
  43. data/lib/xapi/team.rb +44 -0
  44. data/lib/xapi/team_analytics_query.rb +36 -0
  45. data/lib/xapi/verb.rb +35 -0
  46. data/lib/xapi/version.rb +4 -0
  47. data/spec/fixtures/about.json +10 -0
  48. data/spec/fixtures/statement.json +33 -0
  49. data/spec/spec_helper.rb +107 -0
  50. data/spec/support/helpers.rb +60 -0
  51. data/spec/xapi/activity_definition_spec.rb +37 -0
  52. data/spec/xapi/activity_spec.rb +23 -0
  53. data/spec/xapi/agent_account_spec.rb +13 -0
  54. data/spec/xapi/agent_spec.rb +24 -0
  55. data/spec/xapi/attachment_spec.rb +26 -0
  56. data/spec/xapi/context_activities_spec.rb +57 -0
  57. data/spec/xapi/context_spec.rb +32 -0
  58. data/spec/xapi/group_spec.rb +15 -0
  59. data/spec/xapi/interaction_component_spec.rb +18 -0
  60. data/spec/xapi/remote_lrs_spec.rb +46 -0
  61. data/spec/xapi/result_spec.rb +24 -0
  62. data/spec/xapi/score_spec.rb +12 -0
  63. data/spec/xapi/statement_ref_spec.rb +19 -0
  64. data/spec/xapi/statement_spec.rb +73 -0
  65. data/spec/xapi/sub_statement_spec.rb +30 -0
  66. data/spec/xapi/verb_spec.rb +17 -0
  67. data/xapi.gemspec +30 -0
  68. metadata +244 -0
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
7
+
8
+ task :console do
9
+ exec "irb -r xapi -I ./lib"
10
+ end
11
+
12
+
data/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,2 @@
1
+ # encoding: utf-8
2
+ require 'xapi'
data/lib/xapi.rb ADDED
@@ -0,0 +1,224 @@
1
+ # encoding: utf-8
2
+ require 'xapi/errors'
3
+ require 'xapi/enum'
4
+ require 'xapi/version'
5
+ require 'xapi/interaction_type'
6
+ require 'xapi/about'
7
+ require 'xapi/agent_account'
8
+ require 'xapi/agent'
9
+ require 'xapi/group'
10
+ require 'xapi/team'
11
+ require 'xapi/verb'
12
+ require 'xapi/interaction_component'
13
+ require 'xapi/documents/document'
14
+ require 'xapi/score'
15
+ require 'xapi/result'
16
+ require 'xapi/attachment'
17
+ require 'xapi/activity_definition'
18
+ require 'xapi/activity'
19
+ require 'xapi/context_activities'
20
+ require 'xapi/context'
21
+ require 'xapi/statements/statements_base'
22
+ require 'xapi/statement'
23
+ require 'xapi/sub_statement'
24
+ require 'xapi/statement_ref'
25
+ require 'xapi/statements_query'
26
+ require 'xapi/team_analytics_query'
27
+ require 'xapi/statements_query_v095'
28
+ require 'xapi/lrs_response'
29
+ require "xapi/remote_lrs"
30
+ require 'xapi/statements_result'
31
+
32
+ module Xapi
33
+
34
+ # Parameters can be passed for create_agent are:
35
+ # agent_type which is either Agent or Group
36
+ # email, name
37
+ # members[] with hashes having name and email details. This will be given if agent_type is Group
38
+ def self.create_agent(opts={})
39
+ if opts[:agent_type].eql?("Agent")
40
+ Agent.new(mbox: "mailto:#{opts[:email]}", name: "#{opts[:name]}")
41
+ else
42
+ Group.new(members: opts[:members].map{|member| Agent.new(mbox: "mailto:#{member[:email]}", name: "#{member[:name]}") })
43
+ end
44
+ end
45
+
46
+ # Parameters can be passed for create_verb are: id, name
47
+ def self.create_verb(opts={})
48
+ Verb.new(id: opts[:id], display: {"en-US": opts[:name]})
49
+ end
50
+
51
+ # Parameters can be passed for create_activity are: id, name, description, extensions
52
+ def self.create_activity(opts={})
53
+ activity_definition = ActivityDefinition.new(name: {"en-US"=>opts[:name]}, type: opts[:type])
54
+ activity_definition.description = {"en-US" => opts[:description]} if opts[:description].present?
55
+ activity_definition.extensions = opts[:extensions] if opts[:extensions].present?
56
+ Activity.new(id: opts[:id], definition: activity_definition)
57
+ end
58
+
59
+ # Parameters can be passed for create_context_activities are: grouping, category, parent, other
60
+ def self.create_context_activities(opts={})
61
+ ContextActivities.new(opts)
62
+ end
63
+
64
+ # Parameters can be passed for create_context are: registration, extensions, team, instructor, statement, context_activities
65
+ def self.create_context(opts={})
66
+ opts[:language] = 'en-US'
67
+ Context.new(opts)
68
+ end
69
+
70
+ # Parameters can be passed for create_team are: home_page, name
71
+ def self.create_team(opts={})
72
+ team_account = AgentAccount.new(home_page: opts[:home_page], name: opts[:name])
73
+ Team.new(object_type: "Group", account: team_account)
74
+ end
75
+
76
+ # Parameters can be passed for create_team are: object_type, statement_id
77
+ def self.create_statement_ref(opts={})
78
+ StatementRef.new(object_type: opts[:object_type], id: opts[:statement_id])
79
+ end
80
+
81
+ # Parameters can be passed for create_result are: scaled_score or score_details, duration, response, success, completion, extensions
82
+ def self.create_result(opts={})
83
+ score = nil
84
+ if opts[:scaled_score].present?
85
+ score = Score.new(scaled: opts[:scaled_score])
86
+ elsif opts[:score_details].present?
87
+ score = Score.new(raw: opts[:score_details][:raw], min: opts[:score_details][:min], max: opts[:score_details][:max])
88
+ end
89
+ duration = opts[:duration].present? ? opts[:duration] : nil
90
+ result = Result.new(duration: duration, score: score)
91
+ result.response = opts[:response] if opts[:response].present?
92
+ result.success = opts[:success] if opts[:success].present?
93
+ result.completion = opts[:completion] if opts[:completion].present?
94
+ result.extensions = opts[:extensions] if opts[:extensions].present?
95
+ result
96
+ end
97
+
98
+ # Parameters can be passed for create_remote_lrs are: end_point, user_name, password
99
+ def self.create_remote_lrs(opts={})
100
+ RemoteLRS.new(end_point: opts[:end_point], user_name: opts[:user_name], password: opts[:password])
101
+ # lrs_auth_response = remote_lrs.about
102
+ # lrs_auth_response.success ? remote_lrs : nil
103
+ end
104
+
105
+ # Parameters can be passed for create_remote_lrs are: actor, verb, object, context, result
106
+ def self.create_statement(opts={})
107
+ statement = Statement.new(actor: opts[:actor], verb: opts[:verb], object: opts[:object])
108
+ statement.context = opts[:context] if opts[:context].present?
109
+ statement.result = opts[:result] if opts[:result].present?
110
+ statement
111
+ end
112
+
113
+ # Parameters can be passed for create_remote_lrs are: remote_lrs, statement
114
+ def self.post_statement(opts={})
115
+ opts[:remote_lrs].save_statement(opts[:statement])
116
+ end
117
+
118
+ # Parameters can be passed for create_statement_query are: registration_id, verb_id, activity_id, agent_email, agent_name, team_home_page, team_name, search_related_agents, search_related_activities
119
+ def self.create_statement_query(opts={})
120
+ StatementsQuery.new do |s|
121
+ s.registration = opts[:registration_id] if opts[:registration_id].present?
122
+ s.activity_id = opts[:activity_id] if opts[:activity_id].present?
123
+ s.related_activities = opts[:search_related_activities] if opts[:search_related_activities].present?
124
+ agent_object = opts[:agent_email].present? ? create_agent(agent_type: "Agent", email: opts[:agent_email], name: opts[:agent_name]) : create_team(home_page: opts[:team_home_page], name: opts[:team_name])
125
+ s.agent = agent_object if agent_object.present?
126
+ s.related_agents = opts[:team_name].present? ? true : opts[:search_related_agents]
127
+ s.verb_id = opts[:verb_id] if opts[:verb_id].present?
128
+ end
129
+ end
130
+
131
+ # Parameters can be passed for get_statement_by_id are: remote_lrs, statement_id
132
+ def self.get_statements_by_id(opts={})
133
+ response = opts[:remote_lrs].retrieve_statement(opts[:statement_id])
134
+ response.status == 200 ? response.content : nil
135
+ end
136
+
137
+ # Parameters can be passed for get_statements_by_query are: remote_lrs, statement_query
138
+ def self.get_statements_by_query(opts={})
139
+ response = opts[:remote_lrs].query_statements(opts[:statement_query])
140
+ statements = response.content.statements if response.status == 200 && response.content.present?
141
+ statements.present? ? {statements_count: statements.count, statements: statements} : {statements_count: 0, statements: nil}
142
+ end
143
+
144
+ # Parameters can be passed for create_team_analytics_query are: registration_id, verb_id, activity_id, activity_type, team_name, agent_email
145
+ def self.create_team_analytics_query(opts={})
146
+ TeamAnalyticsQuery.new do |s|
147
+ s.registration = opts[:registration_id] if opts[:registration_id].present?
148
+ s.activity_id = opts[:activity_id] if opts[:activity_id].present?
149
+ s.activity_type = opts[:activity_type] if opts[:activity_type].present?
150
+ s.verb_id = opts[:verb_id] if opts[:verb_id].present?
151
+ s.team_name = opts[:team_name] if opts[:team_name].present?
152
+ s.agent_email = opts[:agent_email] if opts[:agent_email].present?
153
+ end
154
+ end
155
+
156
+ # Parameters can be passed for get_team_analytics_by_query are: remote_lrs, team_analytics_query
157
+ def self.get_team_analytics_by_query(opts={})
158
+ response = opts[:remote_lrs].query_team_analytics(opts[:team_analytics_query])
159
+ response.content
160
+ end
161
+
162
+ # Parameters can be passed for create_activity_profile are: remote_lrs, profile_id, activity_object, profile_content
163
+ def self.create_activity_profile(opts={})
164
+ profile_data = Documents::ActivityProfileDocument.new do |pdata|
165
+ pdata.id = opts[:profile_id]
166
+ pdata.activity = opts[:activity_object]
167
+ pdata.content_type = "application/json"
168
+ pdata.content =opts[:profile_content] .to_json
169
+ end
170
+ opts[:remote_lrs].save_activity_profile(profile_data)
171
+ end
172
+
173
+ # Parameters can be passed for get_activity_profile are: remote_lrs, profile_id, activity_object
174
+ def self.get_activity_profile(opts={})
175
+ response = opts[:remote_lrs].retrieve_activity_profile(opts[:profile_id], opts[:activity_object])
176
+ response.status == 200 ? response.content : nil
177
+ end
178
+
179
+ # Parameters can be passed for update_activity_profile are: remote_lrs, profile_id, activity_object, profile_content
180
+ def self.update_activity_profile(opts={})
181
+ profile_data = Documents::ActivityProfileDocument.new do |pdata|
182
+ pdata.id = opts[:profile_id]
183
+ pdata.activity = opts[:activity_object]
184
+ pdata.content_type = "application/json"
185
+ pdata.content = opts[:profile_content] .to_json
186
+ end
187
+ existing_activity_profile = get_activity_profile(remote_lrs: opts[:remote_lrs], profile_id: opts[:profile_id], activity_object: opts[:activity_object])
188
+ opts[:remote_lrs].delete_activity_profile(profile_data) if existing_activity_profile.present?
189
+ profile_data.content = opts[:profile_content].to_json
190
+ opts[:remote_lrs].save_activity_profile(profile_data)
191
+ end
192
+
193
+ # Parameters can be passed for create_agent_profile are: remote_lrs, profile_id, agent_object, profile_content
194
+ def self.create_agent_profile(opts={})
195
+ profile_data = Documents::AgentProfileDocument.new do |pdata|
196
+ pdata.id = opts[:profile_id]
197
+ pdata.agent = opts[:agent_object]
198
+ pdata.content_type = "application/json"
199
+ pdata.content = opts[:profile_content] .to_json
200
+ end
201
+ opts[:remote_lrs].save_agent_profile(profile_data)
202
+ end
203
+
204
+ # Parameters can be passed for get_agent_profile are: remote_lrs, profile_id, agent_object
205
+ def self.get_agent_profile(opts={})
206
+ response = opts[:remote_lrs].retrieve_agent_profile(opts[:profile_id], opts[:agent_object])
207
+ response.status == 200 ? response.content : nil
208
+ end
209
+
210
+ # Parameters can be passed for create_agent_profile are: remote_lrs, profile_id, agent_object, profile_content
211
+ def self.update_agent_profile(opts={})
212
+ profile_data = Documents::AgentProfileDocument.new do |pdata|
213
+ pdata.id = opts[:profile_id]
214
+ pdata.agent = opts[:agent_object]
215
+ pdata.content_type = "application/json"
216
+ pdata.content = opts[:profile_content] .to_json
217
+ end
218
+ existing_agent_profile = get_agent_profile(remote_lrs: opts[:remote_lrs], profile_id: opts[:profile_id], agent_object: opts[:agent_object])
219
+ opts[:remote_lrs].delete_agent_profile(profile_data) if existing_agent_profile.present?
220
+ profile_data.content = opts[:profile_content].to_json
221
+ opts[:remote_lrs].save_agent_profile(profile_data)
222
+ end
223
+
224
+ end
data/lib/xapi/about.rb ADDED
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ module Xapi
3
+ class About
4
+ attr_accessor :versions, :extensions
5
+
6
+ def initialize(options={})
7
+ json = options.fetch(:json, nil)
8
+ if json
9
+ attributes = JSON.parse(json)
10
+ @versions = attributes['version'] if attributes['version']
11
+ @extensions = attributes['extensions'] if attributes['extensions']
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Xapi
3
+ # Activity model class
4
+ class Activity
5
+
6
+ attr_accessor :object_type, :definition
7
+ attr_reader :id
8
+
9
+ def initialize(options={}, &block)
10
+ @object_type = 'Activity'
11
+ json = options.fetch(:json, nil)
12
+ if json
13
+ attributes = JSON.parse(json)
14
+ self.id = attributes['id'] if attributes['id']
15
+ self.definition = ActivityDefinition.new(json: attributes['definition'].to_json) if attributes['definition']
16
+ else
17
+ self.id = options.fetch(:id, nil)
18
+ self.definition = options.fetch(:definition, nil)
19
+ if block_given?
20
+ block[self]
21
+ end
22
+ end
23
+ end
24
+
25
+ def id=(value)
26
+ @id = value
27
+ end
28
+
29
+ def serialize(version)
30
+ node = {}
31
+ node['id'] = id.to_s if id
32
+ node['definition'] = definition.serialize(version) if definition
33
+ node
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,131 @@
1
+ # encoding: utf-8
2
+ module Xapi
3
+ # Activity Definition model class
4
+ class ActivityDefinition
5
+ include Xapi::InteractionType
6
+
7
+ attr_accessor :name, :description, :extensions, :interaction_type, :correct_responses_pattern
8
+ attr_accessor :choices, :scale, :source, :target, :steps
9
+ attr_reader :type, :more_info
10
+
11
+ def initialize(options={}, &block)
12
+ json = options.fetch(:json, nil)
13
+ if json
14
+ attributes = JSON.parse(json)
15
+ self.type = attributes['type'] if attributes['type']
16
+ self.more_info = attributes['moreInfo'] if attributes['moreInfo']
17
+ self.name = attributes['name'] if attributes['name']
18
+ self.description = attributes['description'] if attributes['description']
19
+ self.extensions = attributes['extensions'] if attributes['extensions']
20
+ self.interaction_type = attributes['interactionType'] if attributes['interactionType']
21
+
22
+ if attributes['correctResponsesPattern']
23
+ self.correct_responses_pattern = []
24
+ attributes['correctResponsesPattern'].each do |pattern|
25
+ correct_responses_pattern << pattern
26
+ end
27
+ end
28
+
29
+ if attributes['choices']
30
+ self.choices = []
31
+ attributes['choices'].each do |choice|
32
+ choices << InteractionComponent.new(choice.to_json)
33
+ end
34
+ end
35
+
36
+ if attributes['scale']
37
+ self.scale = []
38
+ attributes['scale'].each do |element|
39
+ scale << InteractionComponent.new(element.to_json)
40
+ end
41
+ end
42
+
43
+ if attributes['source']
44
+ self.source = []
45
+ attributes['source'].each do |element|
46
+ source << InteractionComponent.new(element.to_json)
47
+ end
48
+ end
49
+
50
+ if attributes['target']
51
+ self.target = []
52
+ attributes['target'].each do |element|
53
+ target << InteractionComponent.new(element.to_json)
54
+ end
55
+ end
56
+
57
+ if attributes['steps']
58
+ self.steps = []
59
+ attributes['steps'].each do |element|
60
+ steps << InteractionComponent.new(element.to_json)
61
+ end
62
+ end
63
+
64
+ else
65
+ self.name = options.fetch(:name, nil)
66
+ self.description = options.fetch(:description, nil)
67
+ self.extensions = options.fetch(:extensions, nil)
68
+ self.interaction_type = options.fetch(:interaction_type, nil)
69
+ self.correct_responses_pattern = options.fetch(:correct_responses_pattern, nil)
70
+ self.choices = options.fetch(:choices, nil)
71
+ self.scale = options.fetch(:scale, nil)
72
+ self.source = options.fetch(:source, nil)
73
+ self.target = options.fetch(:target, nil)
74
+ self.type = options.fetch(:type, nil)
75
+ self.more_info = options.fetch(:more_info, nil)
76
+
77
+ if block_given?
78
+ block[self]
79
+ end
80
+ end
81
+ end
82
+
83
+ def type=(value)
84
+ @type = value
85
+ end
86
+
87
+ def more_info=(value)
88
+ @more_info = value
89
+ end
90
+
91
+ def serialize(version)
92
+ node = {}
93
+ node['name'] = name if name
94
+ node['description'] = description if description
95
+ node['type'] = type.to_s if type
96
+ node['moreInfo'] = more_info.to_s if more_info
97
+ node['extensions'] = extensions if extensions
98
+ if interaction_type
99
+ node['interactionType'] = interaction_type.to_s
100
+ case interaction_type
101
+ when Xapi::InteractionType::CHOICE.to_s, Xapi::InteractionType::SEQUENCING.to_s
102
+ if choices && choices.any?
103
+ node['choices'] = choices.map {|element| element.serialize(version)}
104
+ end
105
+ when Xapi::InteractionType::LIKERT.to_s
106
+ if scale && scale.any?
107
+ node['scale'] = scale.map {|element| element.serialize(version)}
108
+ end
109
+ when Xapi::InteractionType::MATCHING.to_s
110
+ if source && source.any?
111
+ node['source'] = source.map {|element| element.serialize(version)}
112
+ end
113
+ if target && target.any?
114
+ node['target'] = target.map {|element| element.serialize(version)}
115
+ end
116
+ when Xapi::InteractionType::PERFORMANCE.to_s
117
+ if steps && steps.any?
118
+ node['steps'] = steps.map {|element| element.serialize(version)}
119
+ end
120
+ end
121
+ end
122
+
123
+ if correct_responses_pattern && correct_responses_pattern.any?
124
+ node['correctResponsesPattern'] = correct_responses_pattern.map {|element| element}
125
+ end
126
+
127
+ node
128
+ end
129
+
130
+ end
131
+ end