growthtribe_xapi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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