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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +28 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +78 -0
- data/LICENSE.txt +22 -0
- data/README.md +299 -0
- data/Rakefile +12 -0
- data/bin/rspec +29 -0
- data/lib/growthtribe_xapi.rb +2 -0
- data/lib/xapi.rb +224 -0
- data/lib/xapi/about.rb +15 -0
- data/lib/xapi/activity.rb +37 -0
- data/lib/xapi/activity_definition.rb +131 -0
- data/lib/xapi/agent.rb +44 -0
- data/lib/xapi/agent_account.rb +33 -0
- data/lib/xapi/attachment.rb +64 -0
- data/lib/xapi/context.rb +54 -0
- data/lib/xapi/context_activities.rb +102 -0
- data/lib/xapi/documents/activity_profile_document.rb +15 -0
- data/lib/xapi/documents/agent_profile_document.rb +15 -0
- data/lib/xapi/documents/document.rb +20 -0
- data/lib/xapi/documents/state_document.rb +15 -0
- data/lib/xapi/enum.rb +42 -0
- data/lib/xapi/errors.rb +9 -0
- data/lib/xapi/group.rb +37 -0
- data/lib/xapi/interaction_component.rb +32 -0
- data/lib/xapi/interaction_type.rb +58 -0
- data/lib/xapi/lrs_response.rb +14 -0
- data/lib/xapi/query_result_format.rb +6 -0
- data/lib/xapi/remote_lrs.rb +416 -0
- data/lib/xapi/result.rb +46 -0
- data/lib/xapi/score.rb +39 -0
- data/lib/xapi/statement.rb +53 -0
- data/lib/xapi/statement_ref.rb +31 -0
- data/lib/xapi/statements/statements_base.rb +70 -0
- data/lib/xapi/statements_query.rb +42 -0
- data/lib/xapi/statements_query_v095.rb +42 -0
- data/lib/xapi/statements_result.rb +17 -0
- data/lib/xapi/sub_statement.rb +19 -0
- data/lib/xapi/tcapi_version.rb +27 -0
- data/lib/xapi/team.rb +44 -0
- data/lib/xapi/team_analytics_query.rb +36 -0
- data/lib/xapi/verb.rb +35 -0
- data/lib/xapi/version.rb +4 -0
- data/spec/fixtures/about.json +10 -0
- data/spec/fixtures/statement.json +33 -0
- data/spec/spec_helper.rb +107 -0
- data/spec/support/helpers.rb +60 -0
- data/spec/xapi/activity_definition_spec.rb +37 -0
- data/spec/xapi/activity_spec.rb +23 -0
- data/spec/xapi/agent_account_spec.rb +13 -0
- data/spec/xapi/agent_spec.rb +24 -0
- data/spec/xapi/attachment_spec.rb +26 -0
- data/spec/xapi/context_activities_spec.rb +57 -0
- data/spec/xapi/context_spec.rb +32 -0
- data/spec/xapi/group_spec.rb +15 -0
- data/spec/xapi/interaction_component_spec.rb +18 -0
- data/spec/xapi/remote_lrs_spec.rb +46 -0
- data/spec/xapi/result_spec.rb +24 -0
- data/spec/xapi/score_spec.rb +12 -0
- data/spec/xapi/statement_ref_spec.rb +19 -0
- data/spec/xapi/statement_spec.rb +73 -0
- data/spec/xapi/sub_statement_spec.rb +30 -0
- data/spec/xapi/verb_spec.rb +17 -0
- data/xapi.gemspec +30 -0
- metadata +244 -0
data/lib/xapi/result.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'active_support/duration'
|
3
|
+
|
4
|
+
module Xapi
|
5
|
+
# Result Model class
|
6
|
+
class Result
|
7
|
+
|
8
|
+
attr_accessor :score, :success, :completion, :duration, :response, :extensions
|
9
|
+
|
10
|
+
def initialize(options={}, &block)
|
11
|
+
json = options.fetch(:json, nil)
|
12
|
+
if json
|
13
|
+
attributes = JSON.parse(json)
|
14
|
+
self.score = Xapi::Score.new(json: attributes['score'].to_json) if attributes['score']
|
15
|
+
self.success = attributes['success'] unless attributes['success'].nil?
|
16
|
+
self.completion = attributes['completion'] unless attributes['completion'].nil?
|
17
|
+
self.duration = ActiveSupport::Duration.parse(attributes['duration']) if attributes['duration']
|
18
|
+
self.response = attributes['response'] if attributes['response']
|
19
|
+
self.extensions = attributes['extensions'] if attributes['extensions']
|
20
|
+
else
|
21
|
+
self.score = options.fetch(:score, nil)
|
22
|
+
self.success = options.fetch(:success, nil)
|
23
|
+
self.completion = options.fetch(:completion, nil)
|
24
|
+
self.duration = options.fetch(:duration, nil)
|
25
|
+
self.response = options.fetch(:response, nil)
|
26
|
+
self.extensions = options.fetch(:extensions, nil)
|
27
|
+
|
28
|
+
if block_given?
|
29
|
+
block[self]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def serialize(version)
|
35
|
+
node = {}
|
36
|
+
node['score'] = score.serialize(version) if score
|
37
|
+
node['success'] = success unless success.nil?
|
38
|
+
node['completion'] = completion unless completion.nil?
|
39
|
+
node['duration'] = duration.iso8601 if duration
|
40
|
+
node['response'] = response if response
|
41
|
+
node['extensions'] = extensions if extensions
|
42
|
+
|
43
|
+
node
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/xapi/score.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
# Score model class
|
4
|
+
class Score
|
5
|
+
|
6
|
+
attr_accessor :scaled, :raw, :min, :max
|
7
|
+
|
8
|
+
def initialize(options={}, &block)
|
9
|
+
json = options.fetch(:json, nil)
|
10
|
+
if json
|
11
|
+
attributes = JSON.parse(json)
|
12
|
+
self.scaled = attributes['scaled'] if attributes['scaled']
|
13
|
+
self.raw = attributes['raw'] if attributes['raw']
|
14
|
+
self.min = attributes['min'] if attributes['min']
|
15
|
+
self.max = attributes['max'] if attributes['max']
|
16
|
+
else
|
17
|
+
self.scaled = options.fetch(:scaled, nil)
|
18
|
+
self.raw = options.fetch(:raw, nil)
|
19
|
+
self.min = options.fetch(:min, nil)
|
20
|
+
self.max = options.fetch(:max, nil)
|
21
|
+
|
22
|
+
if block_given?
|
23
|
+
block[self]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialize(version)
|
30
|
+
node = {}
|
31
|
+
node['scaled'] = scaled if scaled
|
32
|
+
node['raw'] = raw if raw
|
33
|
+
node['min'] = min if min
|
34
|
+
node['max'] = max if max
|
35
|
+
node
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
# Statement Class
|
4
|
+
class Statement < Statements::StatementsBase
|
5
|
+
|
6
|
+
attr_accessor :id, :stored, :authority, :version, :voided
|
7
|
+
|
8
|
+
def initialize(options={}, &block)
|
9
|
+
super(options, &block)
|
10
|
+
json = options.fetch(:json, nil)
|
11
|
+
if json
|
12
|
+
attributes = JSON.parse(json)
|
13
|
+
self.id = attributes['id'] if attributes['id']
|
14
|
+
self.stored = Time.parse(attributes['stored']) if attributes['stored']
|
15
|
+
self.authority = Xapi::Agent.new(json: attributes['authority'].to_json) if attributes['authority']
|
16
|
+
self.version = attributes['version'] if attributes['version']
|
17
|
+
self.voided = attributes['voided'] if attributes['voided']
|
18
|
+
else
|
19
|
+
self.id = options.fetch(:id, nil)
|
20
|
+
self.stored = options.fetch(:stored, nil)
|
21
|
+
self.authority = options.fetch(:authority, nil)
|
22
|
+
self.version = options.fetch(:version, nil)
|
23
|
+
self.voided = options.fetch(:voided, nil)
|
24
|
+
|
25
|
+
if block_given?
|
26
|
+
block[self]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize(version)
|
32
|
+
node = super(version)
|
33
|
+
|
34
|
+
node['id'] = id if id
|
35
|
+
node['stored'] = stored.strftime('%FT%T%:z') if stored
|
36
|
+
node['authority'] = authority.serialize(version) if authority
|
37
|
+
|
38
|
+
if version == Xapi::TCAPIVersion::V095
|
39
|
+
node['voided'] = voided if voided
|
40
|
+
end
|
41
|
+
|
42
|
+
if version.ordinal >= Xapi::TCAPIVersion::V100.ordinal
|
43
|
+
node['version'] = version.to_s if version
|
44
|
+
end
|
45
|
+
node
|
46
|
+
end
|
47
|
+
|
48
|
+
def stamp(id: SecureRandom.uuid, timestamp: Time.now)
|
49
|
+
@id = id
|
50
|
+
@timestamp = timestamp
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
# StatementRef Class used when referencing another statement from a statement's object property
|
4
|
+
class StatementRef
|
5
|
+
|
6
|
+
attr_accessor :object_type, :id
|
7
|
+
|
8
|
+
def initialize(options={}, &block)
|
9
|
+
@object_type = 'StatementRef'
|
10
|
+
json = options.fetch(:json, nil)
|
11
|
+
if json
|
12
|
+
attributes = JSON.parse(json)
|
13
|
+
self.id = attributes['id'] if attributes['id']
|
14
|
+
else
|
15
|
+
self.id = options.fetch(:id, nil)
|
16
|
+
|
17
|
+
if block_given?
|
18
|
+
block[self]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def serialize(version)
|
24
|
+
node = {}
|
25
|
+
node['id'] = id if id
|
26
|
+
node['objectType'] = object_type
|
27
|
+
node
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
module Statements
|
4
|
+
class StatementsBase
|
5
|
+
|
6
|
+
attr_accessor :actor, :verb, :object, :result, :context, :timestamp, :attachments, :voided
|
7
|
+
|
8
|
+
def initialize(options={}, &block)
|
9
|
+
@attachments = []
|
10
|
+
json = options.fetch(:json, nil)
|
11
|
+
if json
|
12
|
+
attributes = JSON.parse(json)
|
13
|
+
self.actor = attributes['actor']['member'] ? Xapi::Group.new(json: attributes['actor'].to_json) : Xapi::Agent.new(json: attributes['actor'].to_json) if attributes['actor']
|
14
|
+
self.verb = Xapi::Verb.new(json: attributes['verb'].to_json) if attributes['verb']
|
15
|
+
object_node = attributes['object']
|
16
|
+
if object_node
|
17
|
+
case object_node['objectType']
|
18
|
+
when 'Group', 'Agent'
|
19
|
+
self.object = Xapi::Agent.new(json: object_node.to_json)
|
20
|
+
when 'StatementRef'
|
21
|
+
self.object = Xapi::StatementRef.new(json: object_node.to_json)
|
22
|
+
when 'SubStatement'
|
23
|
+
self.object = Xapi::SubStatement.new(json: object_node.to_json)
|
24
|
+
else
|
25
|
+
self.object = Xapi::Activity.new(json: object_node.to_json)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
self.result = Xapi::Result.new(json: attributes['result'].to_json) if attributes['result']
|
29
|
+
self.context = Xapi::Context.new(json: attributes['context'].to_json) if attributes['context']
|
30
|
+
self.timestamp = Time.parse(attributes['timestamp']) if attributes['timestamp']
|
31
|
+
self.voided = attributes['voided'] if attributes['voided']
|
32
|
+
if attributes['attachments']
|
33
|
+
attributes['attachments'].each do |attachment|
|
34
|
+
attachments << Xapi::Attachment.new(json: attachment.to_json)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
self.actor = options.fetch(:actor, nil)
|
39
|
+
self.verb = options.fetch(:verb, nil)
|
40
|
+
self.object = options.fetch(:object, nil)
|
41
|
+
self.result = options.fetch(:result, nil)
|
42
|
+
self.context = options.fetch(:context, nil)
|
43
|
+
self.timestamp = options.fetch(:timestamp, nil)
|
44
|
+
self.attachments = options.fetch(:attachments, nil)
|
45
|
+
self.voided = options.fetch(:voided, nil)
|
46
|
+
|
47
|
+
if block_given?
|
48
|
+
block[self]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def serialize(version)
|
54
|
+
node = {}
|
55
|
+
node['actor'] = actor.serialize(version)
|
56
|
+
node['verb'] = verb.serialize(version)
|
57
|
+
node['object'] = object.serialize(version)
|
58
|
+
node['result'] = result.serialize(version) if result
|
59
|
+
node['context'] = context.serialize(version) if context
|
60
|
+
node['timestamp'] = timestamp.strftime('%FT%T%:z') if timestamp
|
61
|
+
if version.ordinal >= Xapi::TCAPIVersion::V100.ordinal
|
62
|
+
if attachments && attachments.any?
|
63
|
+
node['attachments'] = attachments.map {|element| element.serialize(version)}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
node
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
class StatementsQuery
|
4
|
+
|
5
|
+
attr_accessor :version, :verb_id
|
6
|
+
attr_accessor :agent, :activity_id, :registration, :related_activities, :related_agents
|
7
|
+
attr_accessor :stored_since, :stored_until, :limit, :format, :ascending
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
self.version = TCAPIVersion::V101
|
11
|
+
if block_given?
|
12
|
+
block[self]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def verb_id=(value)
|
17
|
+
if value.is_a?(Verb)
|
18
|
+
@verb_id = value.id
|
19
|
+
else
|
20
|
+
@verb_id = value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parameter_map
|
25
|
+
params = {}
|
26
|
+
params['agent'] = agent.object_type.eql?("Group") ? {"account": {"homePage": agent.account.homePage, "name": agent.account.name}}.to_json : {"mbox":agent.mbox}.to_json if agent
|
27
|
+
params['verb'] = verb_id.to_s if verb_id
|
28
|
+
params['activity'] = activity_id.to_s if activity_id
|
29
|
+
params['registration'] = registration if registration
|
30
|
+
params['related_activities'] = related_activities if related_activities
|
31
|
+
params['related_agents'] = related_agents if related_agents
|
32
|
+
params['since'] = stored_since.strftime('%FT%T%:z') if stored_since
|
33
|
+
params['until'] = stored_until.strftime('%FT%T%:z') if stored_until
|
34
|
+
params['limit'] = limit if limit
|
35
|
+
params['format'] = format if format
|
36
|
+
params['ascending'] = ascending if ascending
|
37
|
+
|
38
|
+
params
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
class StatementsQueryV095
|
4
|
+
|
5
|
+
attr_reader :version, :verb_id
|
6
|
+
attr_accessor :object, :registration, :context, :actor, :stored_since, :stored_until, :limit
|
7
|
+
attr_accessor :authoritative, :sparse, :instructor, :ascending
|
8
|
+
|
9
|
+
def initialize(&block)
|
10
|
+
self.version = TCAPIVersion::V095
|
11
|
+
if block_given?
|
12
|
+
block[self]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def verb_id=(value)
|
17
|
+
if value.is_a?(Verb)
|
18
|
+
@verb_id = value.id
|
19
|
+
else
|
20
|
+
@verb_id = Addressable::URI.parse(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parameter_map
|
25
|
+
params = {}
|
26
|
+
params['verb'] = verb_id.to_s if verb_id
|
27
|
+
params['object'] = object.serialize(version) if object
|
28
|
+
params['registration'] = registration if registration
|
29
|
+
params['context'] = context if context
|
30
|
+
params['actor'] = actor if actor
|
31
|
+
params['since'] = stored_since.strftime('%FT%T%:z') if stored_since
|
32
|
+
params['until'] = stored_until.strftime('%FT%T%:z') if stored_until
|
33
|
+
params['limit'] = limit if limit
|
34
|
+
params['authoritative'] = authoritative if authoritative
|
35
|
+
params['sparse'] = sparse if sparse
|
36
|
+
params['instructor'] = instructor.serialize(version) if instructor
|
37
|
+
params['ascending'] = ascending if ascending
|
38
|
+
|
39
|
+
params
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
# Statements result model class, returned by LRS calls to get multiple statements
|
4
|
+
class StatementsResult
|
5
|
+
|
6
|
+
attr_accessor :statements, :more_url
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
json = options.fetch(:json, nil)
|
10
|
+
self.statements = []
|
11
|
+
if json
|
12
|
+
self.statements = json['statements'].map {|statement| Statement.new(json: statement.to_json)} if json['statements']
|
13
|
+
self.more_url = json['more'] if json['more']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
class SubStatement < Statements::StatementsBase
|
4
|
+
|
5
|
+
attr_accessor :object_type
|
6
|
+
|
7
|
+
def initialize(options={}, &block)
|
8
|
+
@object_type = 'SubStatement'
|
9
|
+
super(options, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def serialize(version)
|
13
|
+
node = super(version)
|
14
|
+
node['objectType'] = object_type
|
15
|
+
node
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Xapi
|
3
|
+
module TCAPIVersion
|
4
|
+
|
5
|
+
V101 = {
|
6
|
+
to_s: '1.0.1',
|
7
|
+
get_value: proc{'1.0.1'}
|
8
|
+
}
|
9
|
+
|
10
|
+
V100 = {
|
11
|
+
to_s: '1.0.0',
|
12
|
+
get_value: proc{'1.0.0'}
|
13
|
+
}
|
14
|
+
|
15
|
+
V095 = {
|
16
|
+
to_s: '0.95',
|
17
|
+
get_value: proc{'0.95'}
|
18
|
+
}
|
19
|
+
|
20
|
+
def latest_version
|
21
|
+
V101
|
22
|
+
end
|
23
|
+
|
24
|
+
extend Xapi::Enum
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/xapi/team.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'xapi/tcapi_version'
|
3
|
+
module Xapi
|
4
|
+
# Team model class
|
5
|
+
class Team
|
6
|
+
|
7
|
+
attr_accessor :name, :mbox, :mbox_sha1_sum, :open_id, :account, :object_type
|
8
|
+
|
9
|
+
def initialize(options={}, &block)
|
10
|
+
@object_type = 'Group'
|
11
|
+
json = options.fetch(:json, nil)
|
12
|
+
if json
|
13
|
+
attributes = JSON.parse(json)
|
14
|
+
self.name = attributes['name'] if attributes['name']
|
15
|
+
self.mbox = attributes['mbox'] if attributes['mbox']
|
16
|
+
self.mbox_sha1_sum = attributes['mbox_sha1sum'] if attributes['mbox_sha1sum']
|
17
|
+
self.open_id = attributes['openid'] if attributes['openid']
|
18
|
+
self.account = AgentAccount.new(json: attributes['account'].to_json) if attributes['account']
|
19
|
+
else
|
20
|
+
self.name = options.fetch(:name, nil)
|
21
|
+
self.mbox = options.fetch(:mbox, nil)
|
22
|
+
self.mbox_sha1_sum = options.fetch(:mbox_sha1_sum, nil)
|
23
|
+
self.open_id = options.fetch(:open_id, nil)
|
24
|
+
self.account = options.fetch(:account, nil)
|
25
|
+
|
26
|
+
if block_given?
|
27
|
+
block[self]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def serialize(version)
|
33
|
+
node = {}
|
34
|
+
node['objectType'] = object_type
|
35
|
+
node['name'] = name if name
|
36
|
+
node['mbox'] = mbox if mbox
|
37
|
+
node['mbox_sha1sum'] = mbox_sha1_sum if mbox_sha1_sum
|
38
|
+
node['openid'] = open_id if open_id
|
39
|
+
node['account'] = account.serialize(version) if account
|
40
|
+
node
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|