pupilfirst_xapi 0.1.0 → 0.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99a6dddb084209a85ef5d3f6ad55cf489fb50cf21b0a1f1c1e01a392079a13e9
4
- data.tar.gz: bff106abc8d633185bda3b156203ad901ae0beff5fdb544051014a462405fd67
3
+ metadata.gz: bdb9ed6c9957df10e29f9f8fac0d5a303ac6ed5f962d78bb27af84be1255f61d
4
+ data.tar.gz: 361c1a5767d137ee50a99a191bb9906b1ca295bf6074e2c3568b80a5cf5121ce
5
5
  SHA512:
6
- metadata.gz: b41c20f2967044b42d4d3f11c5307a5970e680f8313d200a91e98e948f0e7ae8053793c976d091372d78eb3a9ede6da505d0253265cd588c51707d355fe26ad5
7
- data.tar.gz: 8a526960635e5065792c221140153834f5eb3f01ab5ef66b221369b034e18510f094e972637702052a2a7a7bfe506fe1762838cf39d3f98a558b7878abf1d2f0
6
+ metadata.gz: ab2a1cba32a1cdc99afeabb7bffc99b022a695989817ac8fe27e7f11894635dedc7befa6a88308af5660ddae6cf9aec8a4d97270bf45e9fb17263eb710d8aa61
7
+ data.tar.gz: e58f22380039a0235534988affdaaa4f01b208b83e43857908d62e20c17d636b548b9a8da96a616e0bb9d1ed03a77b5627488d5c3d0e0bf8e560d658bcc2d24b
@@ -2,6 +2,7 @@ require "action_controller/railtie"
2
2
  require "active_job/railtie"
3
3
  require "growthtribe_xapi"
4
4
  require "pupilfirst_xapi/version"
5
+ require "pupilfirst_xapi/lrs"
5
6
  require "pupilfirst_xapi/outbox"
6
7
  require "pupilfirst_xapi/actors"
7
8
  require "pupilfirst_xapi/objects"
@@ -11,6 +12,7 @@ require "pupilfirst_xapi/statements"
11
12
  module PupilfirstXapi
12
13
  mattr_accessor :uri_for
13
14
  mattr_accessor :repository
15
+ mattr_accessor :lrs
14
16
 
15
17
  Statements.subscribe do |event_type|
16
18
  ActiveSupport::Notifications.subscribe("#{event_type}.pupilfirst") do |_name, _start, finish, _id, payload|
@@ -0,0 +1,24 @@
1
+ require 'xapi'
2
+
3
+ module PupilfirstXapi
4
+ class Lrs
5
+ def initialize(
6
+ end_point: ENV['LRS_ENDPOINT'],
7
+ key: ENV['LRS_KEY'],
8
+ secret: ENV['LRS_SECRET']
9
+ )
10
+ @lrs = end_point && key && secret &&
11
+ Xapi.create_remote_lrs(
12
+ end_point: end_point,
13
+ user_name: key,
14
+ password: secret
15
+ )
16
+ end
17
+
18
+ def call(statement)
19
+ return unless statement && @lrs
20
+
21
+ Xapi.post_statement(remote_lrs: @lrs, statement: statement)
22
+ end
23
+ end
24
+ end
@@ -4,12 +4,12 @@ require_relative 'objects/target'
4
4
 
5
5
  module PupilfirstXapi
6
6
  module Objects
7
- def self.course(course, uri)
8
- Course.new.call(course, uri)
7
+ def self.course(course, uri_for)
8
+ Course.new.call(course, uri_for)
9
9
  end
10
10
 
11
- def self.target(target, uri)
12
- Target.new.call(target, uri)
11
+ def self.target(target, uri_for)
12
+ Target.new.call(target, uri_for)
13
13
  end
14
14
  end
15
15
  end
@@ -1,13 +1,16 @@
1
1
  module PupilfirstXapi
2
2
  module Objects
3
3
  class Course
4
- def call(course, uri)
4
+ def call(course, uri_for)
5
+ uri = uri_for.call(course)
6
+
5
7
  Builder.new(
6
8
  id: uri,
7
9
  type: 'http://adlnet.gov/expapi/activities/product',
8
10
  name: course.name,
9
11
  description: course.description
10
12
  ).tap do |obj|
13
+ obj.with_extension('http://id.tincanapi.com/extension/ending-position', course.targets.count)
11
14
  if course.ends_at.present?
12
15
  duration = ActiveSupport::Duration.build(course.ends_at - course.created_at).iso8601
13
16
  obj.with_extension("http://id.tincanapi.com/extension/planned-duration", duration)
@@ -1,13 +1,19 @@
1
1
  module PupilfirstXapi
2
2
  module Objects
3
3
  class Target
4
- def call(target, uri)
4
+ def call(target, uri_for)
5
+ course = target.course
6
+ target_uri = uri_for.call(target)
7
+
5
8
  Builder.new(
6
- id: uri,
9
+ id: target_uri,
7
10
  type: "http://activitystrea.ms/schema/1.0/task",
8
11
  name: target.title,
9
12
  description: target.description
10
- ).call
13
+ ).tap do |obj|
14
+ obj.with_extension('http://id.tincanapi.com/extension/host', Objects.course(course, uri_for).as_json)
15
+ obj.with_extension('http://id.tincanapi.com/extension/position', target.sort_index)
16
+ end.call
11
17
  end
12
18
  end
13
19
  end
@@ -1,5 +1,4 @@
1
1
  require "active_job"
2
- require 'xapi'
3
2
 
4
3
  module PupilfirstXapi
5
4
  class Outbox
@@ -14,19 +13,11 @@ module PupilfirstXapi
14
13
 
15
14
  def outbox
16
15
  Outbox.new(
17
- lrs: remote_lrs,
16
+ lrs: PupilfirstXapi.lrs || PupilfirstXapi::Lrs.new,
18
17
  repository: PupilfirstXapi.repository,
19
18
  uri_for: PupilfirstXapi.uri_for
20
19
  )
21
20
  end
22
-
23
- def remote_lrs
24
- Xapi.create_remote_lrs(
25
- end_point: ENV['LRS_ENDPOINT'],
26
- user_name: ENV['LRS_KEY'],
27
- password: ENV['LRS_SECRET']
28
- )
29
- end
30
21
  end
31
22
 
32
23
  class << self
@@ -42,8 +33,7 @@ module PupilfirstXapi
42
33
  end
43
34
 
44
35
  def call(**payload)
45
- statement = statement_for(**payload)
46
- Xapi.post_statement(remote_lrs: @lrs, statement: statement) if statement
36
+ @lrs.call(statement_for(**payload))
47
37
  end
48
38
 
49
39
  private
@@ -13,7 +13,7 @@ module PupilfirstXapi
13
13
  Xapi.create_statement(
14
14
  actor: Actors.agent(actor),
15
15
  verb: Verbs::COMPLETED,
16
- object: Objects.course(course, @uri_for.call(course))
16
+ object: Objects.course(course, @uri_for)
17
17
  )
18
18
  end
19
19
  end
@@ -13,7 +13,7 @@ module PupilfirstXapi
13
13
  Xapi.create_statement(
14
14
  actor: Actors.agent(actor),
15
15
  verb: Verbs::REGISTERED,
16
- object: Objects.course(course, @uri_for.call(course))
16
+ object: Objects.course(course, @uri_for)
17
17
  )
18
18
  end
19
19
  end
@@ -16,7 +16,7 @@ module PupilfirstXapi
16
16
  Xapi.create_statement(
17
17
  actor: Actors.agent(actor),
18
18
  verb: Verbs::COMPLETED_ASSIGNMENT,
19
- object: Objects.target(target, @uri_for.call(target))
19
+ object: Objects.target(target, @uri_for)
20
20
  )
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module PupilfirstXapi
2
- VERSION = '0.1.0'
2
+ VERSION = '0.3.2'
3
3
  end
@@ -15,13 +15,20 @@ RSpec.describe "#xapi", type: :job, perform_jobs: true do
15
15
  description: 'These guides are designed to make you immediately productive with Rails',
16
16
  created_at: Time.new(2021,01,01),
17
17
  ends_at: nil,
18
- uri: 'https://guides.rubyonrails.org/')
18
+ uri: 'https://guides.rubyonrails.org/',
19
+ targets: [
20
+ double(:target, title: '1st target', description: 'Seems easy'),
21
+ double(:target, title: '2nd target', description: 'Seems not easy')
22
+ ]
23
+ )
19
24
  }
20
25
  let(:getting_started) {
21
26
  double(:target,
22
27
  title: 'Getting Started with Rails',
23
28
  description: 'This guide covers getting up and running with Ruby on Rails.',
24
- uri: 'https://guides.rubyonrails.org/getting_started.html')
29
+ uri: 'https://guides.rubyonrails.org/getting_started.html',
30
+ course: ror_guides
31
+ )
25
32
  }
26
33
  let(:good_one) { double(:timeline_event, target: getting_started, passed?: true) }
27
34
  let(:bad_one) { double(:timeline_event, target: getting_started, passed?: false) }
@@ -75,6 +82,7 @@ RSpec.describe "#xapi", type: :job, perform_jobs: true do
75
82
  name: {'en-US' => 'Ruby on Rails Guides'},
76
83
  description: {'en-US' => 'These guides are designed to make you immediately productive with Rails'},
77
84
  type: 'http://adlnet.gov/expapi/activities/product',
85
+ extensions: {"http://id.tincanapi.com/extension/ending-position"=>2}
78
86
  },
79
87
  },
80
88
  timestamp: timestamp.iso8601,
@@ -88,7 +96,7 @@ RSpec.describe "#xapi", type: :job, perform_jobs: true do
88
96
  'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
89
97
  'Authorization'=>'Basic a2V5OnNlY3JldA==',
90
98
  'Content-Type'=>'application/json',
91
- 'User-Agent'=>'Faraday v1.3.0',
99
+ 'User-Agent'=>'Faraday v1.3.1',
92
100
  'X-Experience-Api-Version'=>'1.0.1'
93
101
  }
94
102
  ).to_return(status: 204, body: "", headers: {})
data/spec/outbox_spec.rb CHANGED
@@ -4,8 +4,8 @@ module PupilfirstXapi
4
4
  RSpec.describe Outbox do
5
5
  let(:timestamp) { Time.now }
6
6
  let(:john) { double(:john, name: 'John Doe', email: 'john@doe.com') }
7
- let(:course) { double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil) }
8
- let(:target) { double(:target, title: '1st target', description: 'Seems easy') }
7
+ let(:course) { double(:course, id: 32, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil, targets: []) }
8
+ let(:target) { double(:target, title: '1st target', description: 'Seems easy', course: course, sort_index: 7) }
9
9
  let(:good_one) { double(:timeline_event, target: target, passed?: true) }
10
10
  let(:bad_one) { double(:timeline_event, target: target, passed?: false) }
11
11
 
data/spec/spec_helper.rb CHANGED
@@ -50,7 +50,9 @@ class FakeLrs
50
50
  end
51
51
  attr_reader :statements
52
52
 
53
- def save_statement(statement)
53
+ def call(statement)
54
+ return unless statement
55
+
54
56
  @statements << statement
55
57
  end
56
58
  end
@@ -5,7 +5,11 @@ module PupilfirstXapi
5
5
  RSpec.describe CourseCompleted do
6
6
  it do
7
7
  john = double(:john, name: 'John Doe', email: 'john@doe.com')
8
- course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil)
8
+ course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil,
9
+ targets: [
10
+ double(:target, title: '1st target', description: 'Seems easy'),
11
+ double(:target, title: '2nd target', description: 'Seems not easy')
12
+ ])
9
13
  data = {
10
14
  course: { 456 => course },
11
15
  user: { 123 => john },
@@ -5,7 +5,11 @@ module PupilfirstXapi
5
5
  RSpec.describe CourseRegistered do
6
6
  it do
7
7
  john = double(:john, name: 'John Doe', email: 'john@doe.com')
8
- course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil)
8
+ course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil,
9
+ targets: [
10
+ double(:target, title: '1st target', description: 'Seems easy'),
11
+ double(:target, title: '2nd target', description: 'Seems not easy')
12
+ ])
9
13
  data = {
10
14
  course: { 456 => course },
11
15
  user: { 123 => john },
@@ -25,7 +29,9 @@ module PupilfirstXapi
25
29
  expect(xapi.object.definition.type).to eq 'http://adlnet.gov/expapi/activities/product'
26
30
  expect(xapi.object.definition.name).to eq({'en-US' => 'Rails for Begginers'})
27
31
  expect(xapi.object.definition.description).to eq({'en-US' => 'Seems easy'})
28
- expect(xapi.object.definition.extensions).to eq nil
32
+ expect(xapi.object.definition.extensions).to eq ({
33
+ "http://id.tincanapi.com/extension/ending-position" => 2
34
+ })
29
35
  end
30
36
 
31
37
  it do
@@ -34,7 +40,11 @@ module PupilfirstXapi
34
40
  duration = ActiveSupport::Duration.build(ends_at - starts_at).iso8601
35
41
 
36
42
  john = double(:john, name: 'John Doe', email: 'john@doe.com')
37
- course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: starts_at, ends_at: ends_at)
43
+ course = double(:course, name: 'Rails for Begginers', description: 'Seems easy', created_at: starts_at, ends_at: ends_at,
44
+ targets: [
45
+ double(:target, title: '1st target', description: 'Seems easy'),
46
+ double(:target, title: '2nd target', description: 'Seems not easy')
47
+ ])
38
48
  data = {
39
49
  course: { 456 => course },
40
50
  user: { 123 => john },
@@ -54,7 +64,10 @@ module PupilfirstXapi
54
64
  expect(xapi.object.definition.type).to eq 'http://adlnet.gov/expapi/activities/product'
55
65
  expect(xapi.object.definition.name).to eq({'en-US' => 'Rails for Begginers'})
56
66
  expect(xapi.object.definition.description).to eq({'en-US' => 'Seems easy'})
57
- expect(xapi.object.definition.extensions).to eq({"http://id.tincanapi.com/extension/planned-duration" => duration})
67
+ expect(xapi.object.definition.extensions).to eq({
68
+ "http://id.tincanapi.com/extension/planned-duration" => duration,
69
+ "http://id.tincanapi.com/extension/ending-position" => 2
70
+ })
58
71
  end
59
72
  end
60
73
  end
@@ -4,7 +4,12 @@ module PupilfirstXapi
4
4
  module Statements
5
5
  RSpec.describe TargetCompleted do
6
6
  it do
7
- target = double(:target, title: '1st target', description: 'Seems easy')
7
+ course = double(:course, id: 17, name: 'Rails for Begginers', description: 'Seems easy', created_at: 1.week.ago, ends_at: nil,
8
+ targets: [
9
+ double(:target, title: '1st target', description: 'Seems easy'),
10
+ double(:target, title: '2nd target', description: 'Seems not easy')
11
+ ])
12
+ target = double(:target, title: '1st target', course: course, description: 'Seems easy', sort_index: 5)
8
13
  submission = double(:timeline_event, target: target, passed?: true)
9
14
  john = double(:john, name: 'John Doe', email: 'john@doe.com')
10
15
  data = {
@@ -12,7 +17,7 @@ module PupilfirstXapi
12
17
  user: { 123 => john },
13
18
  }
14
19
  repository = ->(klass, resource_id) { data.dig(klass, resource_id) }
15
- uri_for = ->(obj) { obj == target ? 'target-1' : nil }
20
+ uri_for = ->(obj) { obj == target ? 'target-1' : obj == course ? 'course-1' : nil }
16
21
 
17
22
  xapi = TargetCompleted.new(repository, uri_for).call(actor_id: 123, resource_id: 456)
18
23
 
@@ -26,10 +31,11 @@ module PupilfirstXapi
26
31
  expect(xapi.object.definition.type).to eq 'http://activitystrea.ms/schema/1.0/task'
27
32
  expect(xapi.object.definition.name).to eq({'en-US' => '1st target'})
28
33
  expect(xapi.object.definition.description).to eq({'en-US' => 'Seems easy'})
34
+ expect(xapi.object.definition.extensions['http://id.tincanapi.com/extension/host']['id']).to eq 'course-1'
29
35
  end
30
36
 
31
37
  it 'no-op when submission is not passed' do
32
- target = double(:target, title: '1st target', description: 'Seems easy')
38
+ target = double(:target, title: '1st target', description: 'Seems easy', sort_index: 3)
33
39
  submission = double(:timeline_event, target: target, passed?: false)
34
40
  john = double(:john, name: 'John Doe', email: 'john@doe.com')
35
41
  data = {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pupilfirst_xapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - GrowthTribe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-02 00:00:00.000000000 Z
11
+ date: 2021-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.0.1
39
+ version: 0.0.2
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: 0.0.1
46
+ version: 0.0.2
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec-rails
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -98,6 +98,7 @@ files:
98
98
  - Rakefile
99
99
  - lib/pupilfirst_xapi.rb
100
100
  - lib/pupilfirst_xapi/actors.rb
101
+ - lib/pupilfirst_xapi/lrs.rb
101
102
  - lib/pupilfirst_xapi/objects.rb
102
103
  - lib/pupilfirst_xapi/objects/builder.rb
103
104
  - lib/pupilfirst_xapi/objects/course.rb
@@ -116,7 +117,7 @@ files:
116
117
  - spec/rails_helper.rb
117
118
  - spec/spec_helper.rb
118
119
  - spec/statements/course_completed_spec.rb
119
- - spec/statements/course_redistered_spec.rb
120
+ - spec/statements/course_registered_spec.rb
120
121
  - spec/statements/target_completed_spec.rb
121
122
  homepage: https://github.com/growthtribeacademy/pupilfirst-xapi
122
123
  licenses:
@@ -152,5 +153,5 @@ test_files:
152
153
  - spec/rails_helper.rb
153
154
  - spec/spec_helper.rb
154
155
  - spec/statements/course_completed_spec.rb
155
- - spec/statements/course_redistered_spec.rb
156
+ - spec/statements/course_registered_spec.rb
156
157
  - spec/statements/target_completed_spec.rb