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