kgrift 1.3.108

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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/KGrift/Gemfile +22 -0
  3. data/KGrift/README.md +66 -0
  4. data/KGrift/bin/kgrift +11 -0
  5. data/KGrift/grifter.yml +224 -0
  6. data/KGrift/internal_test_graphs/basic_test_graph_definition.yml +2915 -0
  7. data/KGrift/internal_test_graphs/unicode_test_graph_definition.yml +3070 -0
  8. data/KGrift/knewton_grifts/analytics_grifts.rb +103 -0
  9. data/KGrift/knewton_grifts/async_helper_grifts.rb +63 -0
  10. data/KGrift/knewton_grifts/authenticator_grifts.rb +46 -0
  11. data/KGrift/knewton_grifts/basic_grifts.rb +29 -0
  12. data/KGrift/knewton_grifts/batch_grifts.rb +14 -0
  13. data/KGrift/knewton_grifts/content_collection_grifts.rb +204 -0
  14. data/KGrift/knewton_grifts/content_collection_v1_grifts.rb +521 -0
  15. data/KGrift/knewton_grifts/content_eid_grifts.rb +41 -0
  16. data/KGrift/knewton_grifts/copy_grifts.rb +151 -0
  17. data/KGrift/knewton_grifts/deprecated_graph_and_taxonomy_grifts.rb +353 -0
  18. data/KGrift/knewton_grifts/goal_grifts.rb +203 -0
  19. data/KGrift/knewton_grifts/graph_and_taxonomy_grifts.rb +136 -0
  20. data/KGrift/knewton_grifts/graph_create_grifts.rb +34 -0
  21. data/KGrift/knewton_grifts/graph_query_grifts.rb +448 -0
  22. data/KGrift/knewton_grifts/graph_tools_grifts.rb +151 -0
  23. data/KGrift/knewton_grifts/graph_validation_grifts.rb +447 -0
  24. data/KGrift/knewton_grifts/helper_grifts.rb +92 -0
  25. data/KGrift/knewton_grifts/jmeter_data_grifts.rb +56 -0
  26. data/KGrift/knewton_grifts/learning_instance_grifts.rb +46 -0
  27. data/KGrift/knewton_grifts/looper_grifts.rb +34 -0
  28. data/KGrift/knewton_grifts/moxy_grifts.rb +64 -0
  29. data/KGrift/knewton_grifts/oauth_grifts.rb +182 -0
  30. data/KGrift/knewton_grifts/partner_grifts.rb +70 -0
  31. data/KGrift/knewton_grifts/partner_support_grifts.rb +85 -0
  32. data/KGrift/knewton_grifts/recommendation_setup_grifts.rb +215 -0
  33. data/KGrift/knewton_grifts/registration_grifts.rb +159 -0
  34. data/KGrift/knewton_grifts/registration_info_grifts.rb +23 -0
  35. data/KGrift/knewton_grifts/report_grifts.rb +122 -0
  36. data/KGrift/knewton_grifts/shell_command_grifts.rb +21 -0
  37. data/KGrift/knewton_grifts/student_flow_grifts.rb +560 -0
  38. data/KGrift/knewton_grifts/tag_grifts.rb +41 -0
  39. data/KGrift/knewton_grifts/test_data_grifts.rb +328 -0
  40. data/KGrift/knewton_grifts/test_user_grifts.rb +264 -0
  41. data/KGrift/lib/dtrace.rb +20 -0
  42. data/KGrift/lib/kgrift.rb +7 -0
  43. data/KGrift/test_data_generators/basic_book_and_taxonomies.rb +35 -0
  44. data/KGrift/test_data_generators/lo_test_graph.rb +34 -0
  45. data/KGrift/test_data_generators/partner_owned_book_and_taxonomies.rb +28 -0
  46. data/KGrift/test_data_generators/partner_owned_book_and_taxonomies_unicode.rb +28 -0
  47. data/KGrift/test_data_generators/sandcastle_book_and_taxonomies.rb +13 -0
  48. data/KGrift/test_data_generators/sandcastle_book_and_taxonomies.yml +3709 -0
  49. data/KGrift/test_data_generators/sandcastle_graph.rb +8 -0
  50. data/KGrift/test_data_generators/sandcastle_graph_definition.json +4483 -0
  51. data/KGrift/test_data_generators/sandcastle_graph_full.rb +7 -0
  52. data/KGrift/test_data_generators/sandcastle_taxonomies.yml +378 -0
  53. data/KGrift/test_data_generators/sandcastle_with_taxons.rb +56 -0
  54. data/KGrift/test_data_generators/sandcastle_with_taxons.yml +3994 -0
  55. data/KGrift/test_data_generators/test_users_and_partners.rb +76 -0
  56. data/kgrift.gemspec +43 -0
  57. metadata +144 -0
@@ -0,0 +1,70 @@
1
+ #NOTICE: this only lists test partners, which does not include the Knewton partner
2
+ def list_partners overrides={}
3
+ params = {
4
+ "test_partners" => true
5
+ }.merge(overrides).delete_if{|k,v| v.nil?}
6
+
7
+ Log.info "Listing all partners"
8
+ kapi.get '/v0/partners?' + URI.encode_www_form(params), timeout: 3600
9
+ end
10
+
11
+ def list_prod_partners overrides={}
12
+ params = {
13
+ 'test_partners' => false,
14
+ }.merge(overrides)
15
+ list_partners params
16
+ end
17
+
18
+ def create_partner overrides={}
19
+ Log.info "Creating a partner"
20
+ kapi.post '/v0/partners', {
21
+ 'name' => random_string,
22
+ 'password' => random_string,
23
+ 'is_testing' => true,
24
+ 'display_name' => 'KGriftTestingPartner_' + random_string(16),
25
+ 'rate_limit_multiplier' => 1.0,
26
+ }.merge(overrides)
27
+ end
28
+
29
+ def update_partner id, payload
30
+ Log.info "Updating partner: #{id}"
31
+ kapi.put "/v0/partners/#{id}", payload
32
+ end
33
+
34
+ def get_partner id
35
+ Log.info "Getting a partner: " + id
36
+ kapi.get "/v0/partners/#{id}"
37
+ end
38
+
39
+ def delete_partner id
40
+ Log.info "Deleting a partner: " + id
41
+ kapi.delete "/v0/partners/#{id}"
42
+ end
43
+
44
+ def create_system_user id
45
+ Log.info "Creating a system user for partner: " + id
46
+ kapi.post "/v0/partners/#{id}/system-user", nil
47
+ end
48
+
49
+ #this will not raise an error if 409 conflict
50
+ # is returned on create call
51
+ def ensure_partner_exists overrides={}
52
+ Log.info 'Ensuring partner exists: ' + overrides['name'].to_s
53
+ create_partner overrides
54
+ return true
55
+ rescue Grifter::RequestException => e
56
+ if e.code == 409
57
+ Log.debug "Partner already exists"
58
+ return true
59
+ else
60
+ raise e
61
+ end
62
+ end
63
+
64
+
65
+ def set_partner_rate_limit_multiplier id, multiplier
66
+ partner = get_partner id
67
+ update_payload = partner.merge 'rate_limit_multiplier' => multiplier
68
+ update_payload.delete 'id'
69
+ update_partner id, update_payload
70
+ end
@@ -0,0 +1,85 @@
1
+ #add_new_prod_partner is used for making production partners
2
+ #it makes system users as well
3
+ #by default it makes 1 system user and 1 old-style-system-user
4
+ #you can alter either count through the options passed in
5
+ def add_new_prod_partner display_name, options={}
6
+ if !display_name.kind_of?(String) || display_name.length < 3
7
+ raise "You must pass in a display name that is at least 3 characters long"
8
+ end
9
+ options.merge!({ 'display_name' => display_name })
10
+ set_prod_mode
11
+ set_account :prod_knerd
12
+ partner_data = add_new_partner options
13
+ print "\n\nNEW PARTNER:\n#{partner_data.to_yaml}\n"
14
+ partner_data
15
+ end
16
+
17
+ #add new test partner should be used anytime we are making
18
+ #a partner for internal testing use. Test partner are NEVER
19
+ #to be given externally as they are subject to being deleted without notice
20
+ def add_new_partner options={}
21
+
22
+ options = {
23
+ 'num_system_users' => 1,
24
+ 'is_testing' => false,
25
+ 'filename' => 'new_partner_data.json',
26
+ 'display_name' => 'KnewtonTestingPartner_' + random_string(16),
27
+ 'rate_limit_multiplier' => 1.0,
28
+ }.merge(options)
29
+
30
+ new_partner_data = {
31
+ 'client_id' => options.fetch('client_id', random_string(32)),
32
+ 'client_secret' => options.fetch('client_secret', random_string(48)),
33
+ }
34
+
35
+ partner = create_partner 'name' => new_partner_data['client_id'],
36
+ 'password' => new_partner_data['client_secret'],
37
+ 'is_testing' => options['is_testing'],
38
+ 'display_name' => options['display_name'],
39
+ 'rate_limit_multiplier' => options['rate_limit_multiplier']
40
+
41
+ new_partner_data['partner_id'] = partner['id']
42
+
43
+ if options['num_system_users'] > 0
44
+ new_partner_data['system_users'] = options['num_system_users'].times.map do
45
+ new_system_user = create_system_user new_partner_data['partner_id']
46
+ {
47
+ 'external_user_id' => new_system_user['external_user_id'],
48
+ 'account_id' => new_system_user['id'],
49
+ }
50
+ end
51
+ end
52
+
53
+ new_partner_data['created_on'] = DateTime.now.to_s
54
+ new_partner_data['created_by'] = Etc.getlogin
55
+
56
+ File.open(options['filename'], 'w') do |f|
57
+ f.write(JSON.pretty_generate(new_partner_data))
58
+ Log.warn "Wrote the new partner data to #{options['filename']}"
59
+ end
60
+
61
+ return new_partner_data
62
+ end
63
+
64
+ def set_prod_mode
65
+ grifter_configuration[:services].keys.each do |svc|
66
+ self.send(svc).headers.delete 'knewton-test'
67
+ end
68
+ nil
69
+ end
70
+
71
+ def set_test_mode
72
+ grifter_configuration[:services].keys.each do |svc|
73
+ self.send(svc).headers['knewton-test'] = 'true'
74
+ end
75
+ nil
76
+ end
77
+
78
+ def get_client_id_from_partner_id partner_id
79
+ partner_record = nil
80
+ as_account :knerd do
81
+ partner_record = get_partner partner_id
82
+ end
83
+ partner_record['name']
84
+ end
85
+
@@ -0,0 +1,215 @@
1
+ """
2
+ Grifts to setup state to test recommendations.
3
+
4
+ Use to setup tests verifying rec contracts. The terminology used is specified in the beginning of
5
+ the Recommendations Contracts document:
6
+ https://docs.google.com/document/d/1s0gBAPbBKdCUmkBmLh36tQk1-s9B7VD14sz22vWm4Ns/
7
+ """
8
+
9
+ MAX_RANDOM_HISTORY_EVENTS=20
10
+
11
+ def setup_test_scenario scenario, graph_type
12
+ set_account(:partner)
13
+ test_data = {}
14
+ #get graph, create learning instance/goal/student/registration
15
+ test_data['graph'] = (get_test_data :simple_graphs)[graph_type]
16
+ test_data['learning_instance'] = create_learning_instance graph_id: test_data['graph']['id']
17
+ test_data['goal'] = generate_specified_goal test_data['graph'], test_data['learning_instance']['id'], scenario['goal'], scenario['target_date_offset']
18
+ test_data['student'] = add_new_student_to_learning_instance test_data['learning_instance']['id']
19
+
20
+ generate_student_history scenario['history'], test_data
21
+
22
+ test_data
23
+ end
24
+
25
+ #Generate student history of a specified type-- currently either None or Any (random)
26
+ def generate_student_history history_type, test_data
27
+ r = Random.new
28
+ if ENV.has_key? "REC_SEED"
29
+ r = Random.new ENV['REC_SEED']
30
+ end
31
+
32
+ case history_type
33
+ when "None"
34
+ return
35
+ when "Any"
36
+ num_events = r.rand(MAX_RANDOM_HISTORY_EVENTS)
37
+ num_events.times do
38
+ send_random_event_on_graph test_data['student']['registration_id'], test_data['graph']
39
+ end
40
+ end
41
+ end
42
+
43
+ #Default goal settings
44
+ DEFAULT_TARGET_SCORE = 0.7
45
+ DEFAULT_TARGET_DATE_OFFSET = 7
46
+ def generate_specified_goal graph, learning_instance_id, goal_type, target_date_offset=DEFAULT_TARGET_DATE_OFFSET
47
+ case goal_type
48
+ when "G[T][T]"
49
+ #Goal with on single-concept graph of concept T, with:
50
+ # - a single arbitrary assessment module within concept T
51
+ # - all modules under concept T recommendable.
52
+
53
+ #select the single concept T
54
+ concept = find_concept_by_name graph, 'T'
55
+
56
+ #Pick the single assessment module under concept T.
57
+ assessing_module = find_associated_assessing_bndl graph, concept['id']
58
+
59
+ #Pick the all modules under concept T as recommendable.
60
+ rec_modules = find_associated_assessing_atoms graph, concept['id']
61
+
62
+ goal = create_goal learning_instance_id, {
63
+ 'target_modules' => [ {
64
+ 'module_id' => assessing_module,
65
+ 'target_score' => DEFAULT_TARGET_SCORE,
66
+ 'target_date' => days_from_now(target_date_offset),
67
+ }],
68
+ 'recommendable_modules' => rec_modules.map{|m| { "module_id" => m } },
69
+ }
70
+ when "G[T][P1,T]"
71
+ #Goal with on single-concept graph of concept T, with:
72
+ # - a single arbitrary assessment module within concept T
73
+ # - all modules under concepts P1 and T recommendable.
74
+
75
+ #select concepts
76
+ concept_t = find_concept_by_name graph, 'T'
77
+ concept_p1 = find_concept_by_name graph, 'P1'
78
+
79
+ #Pick the single assessment module under concept T.
80
+ assessing_module = find_associated_assessing_bndl graph, concept_t['id']
81
+
82
+ #Pick the all modules under concept T as recommendable.
83
+ rec_modules = []
84
+ rec_modules.concat( find_associated_assessing_atoms graph, concept_t['id'] )
85
+ rec_modules.concat( find_associated_assessing_atoms graph, concept_p1['id'] )
86
+
87
+ goal = create_goal learning_instance_id, {
88
+ 'target_modules' => [ {
89
+ 'module_id' => assessing_module,
90
+ 'target_score' => DEFAULT_TARGET_SCORE,
91
+ 'target_date' => days_from_now(target_date_offset),
92
+ }],
93
+ 'recommendable_modules' => rec_modules.map{|m| { "module_id" => m } },
94
+ }
95
+ when "G[T][all]"
96
+ #Goal with on single-concept graph of concept T, with:
97
+ # - a single arbitrary assessment module within concept T
98
+ # - all atoms in the graph recommendable.
99
+
100
+ #select concepts
101
+ concept_t = find_concept_by_name graph, 'T'
102
+
103
+ #Pick the single assessment module under concept T.
104
+ assessing_module = find_associated_assessing_bndl graph, concept_t['id']
105
+
106
+ #Pick the all atoms as recommendable.
107
+ rec_modules = find_all_atom_ids graph
108
+
109
+ goal = create_goal learning_instance_id, {
110
+ 'target_modules' => [ {
111
+ 'module_id' => assessing_module,
112
+ 'target_score' => DEFAULT_TARGET_SCORE,
113
+ 'target_date' => days_from_now(target_date_offset),
114
+ }],
115
+ 'recommendable_modules' => rec_modules.map{|m| { "module_id" => m } },
116
+ }
117
+ when "G[P1][all]"
118
+ #Goal with on single-concept graph of concept P1, with:
119
+ # - a single arbitrary assessment module within concept P1
120
+ # - all atoms in the graph recommendable.
121
+
122
+ #select concepts
123
+ concept_p1 = find_concept_by_name graph, 'P1'
124
+
125
+ #Pick the single assessment module under concept P1.
126
+ assessing_module = find_associated_assessing_bndl graph, concept_p1['id']
127
+
128
+ #Pick the all atoms as recommendable.
129
+ rec_modules = find_all_atom_ids graph
130
+
131
+ goal = create_goal learning_instance_id, {
132
+ 'target_modules' => [ {
133
+ 'module_id' => assessing_module,
134
+ 'target_score' => DEFAULT_TARGET_SCORE,
135
+ 'target_date' => days_from_now(target_date_offset),
136
+ }],
137
+ 'recommendable_modules' => rec_modules.map{|m| { "module_id" => m } },
138
+ }
139
+ else
140
+ throw "Unrecognized goal type #{goal_type}"
141
+ end
142
+ end
143
+
144
+ def complete_goal_with_percentage_correct registration_id, goal_id, percentage_correct, options={}
145
+ starting_event_threshold = 1.0 - percentage_correct
146
+
147
+ completion_data = complete_goal registration_id,
148
+ goal_id,
149
+ options.merge({:starting_event_threshold=>starting_event_threshold, :event_threshold_multiplier=>1.0})
150
+
151
+ completion_data
152
+ end
153
+
154
+ def complete_goal_with_percentage_correct_per_concept graph, registration_id, goal_id, percentages_correct, options={}
155
+ concept_thresholds = []
156
+
157
+ percentages_correct.each do |concept,percentage|
158
+ concept_thresholds << {
159
+ 'id'=> (find_concept_by_name graph, concept)['id'],
160
+ 'current_threshold' => (1.0-percentage),
161
+ 'threshold_multiplier' => 1.0,
162
+ 'num_fails_before_success' => 0,
163
+ }
164
+ end
165
+
166
+ completion_data = complete_goal registration_id,
167
+ goal_id,
168
+ options.merge({:concept_thresholds=>concept_thresholds})
169
+
170
+ completion_data
171
+ end
172
+
173
+ #Parses test data as used in the recommendations contracts tests, stripping irrelevent data and applying readable names
174
+ def humanize_completion_data test_data, graph_type, scenario_title, scenario
175
+ human_data = {}
176
+ human_data['date'] = Time.now
177
+ human_data['env'] = ENV['GRIFTER_ENVIRONMENT']
178
+ human_data['contract'] = scenario_title
179
+ human_data['graph_type'] = graph_type
180
+ human_data['goal_type'] = scenario['goal']
181
+ human_data['is_goal_complete'] = test_data['completion_data']['event_count'] <= scenario['max_adaptive_cycles']
182
+ human_data['contract_vars'] = test_data['contract_vars']
183
+ if test_data['preliminary_event_bodies']
184
+ human_data['preliminary_events'] = test_data['preliminary_event_bodies'].map do |event|
185
+ humanize_event_body test_data['graph'], event
186
+ end
187
+ end
188
+ human_data['adaptive_cycles'] = test_data['completion_data']['event_bodies_sent'].map do |event|
189
+ humanize_event_body test_data['graph'], event
190
+ end
191
+ human_data['concepts'] = humanize_concept_data test_data['graph']
192
+
193
+ human_data
194
+ end
195
+
196
+ def humanize_event_body graph, event
197
+ node = get_node_with_concept_and_content_type graph, event['module_id']
198
+ cycle_data = {
199
+ 'concept' => node['concept']['name'],
200
+ 'content_type' => node['content_type'],
201
+ 'is_correct' => event['is_correct'],
202
+ 'module_id' => event['module_id'],
203
+ }
204
+ end
205
+
206
+ def humanize_concept_data graph
207
+ concepts = (find_all_concept_ids graph).map do |concept|
208
+ concept = get_node_by_id graph, concept
209
+ {'id' => concept['id'], 'name' => concept['name']}
210
+ end
211
+ end
212
+
213
+ def write_contract_yaml_report contract_filename, report_data
214
+ File.open("reports/contract_#{contract_filename}.yml", 'w') {|f| f.write YAML::dump(report_data) }
215
+ end
@@ -0,0 +1,159 @@
1
+ ##STUFF RELATING TO REGISTRATION RESOURCES
2
+ def create_registration overrides={}
3
+ Log.info "Creating a registration"
4
+ # if account_id was passed in, we'll use that account id
5
+ # but, if account_id not provided, we'll make an account and return its details
6
+ account = nil
7
+ unless overrides['account_id']
8
+ account = create_account
9
+ overrides['account_id'] = account['id']
10
+ end
11
+ reg = kapi.post '/v0/registrations', {
12
+ 'type' => 'learner',
13
+ 'account_id' => nil,
14
+ 'learning_instance_id' => '456',
15
+ }.merge(overrides)
16
+ reg['external_user_id'] = account['external_user_id'] if account
17
+ reg
18
+ end
19
+
20
+ def make_account_instructor_of account_id, learning_instance_id
21
+ Log.info "Creating a registration of type instructor for learning instance " + learning_instance_id + " account_id " + account_id
22
+ create_registration 'learning_instance_id' => learning_instance_id,
23
+ 'account_id' => account_id,
24
+ 'type' => "instructor"
25
+ end
26
+
27
+
28
+ def add_new_student_to_learning_instance learning_instance_id, client_credentials=nil, options={}
29
+ client_credentials = get_client_credentials(:knewton) unless client_credentials
30
+ account = create_account
31
+ external_user_id = account['external_user_id']
32
+ account_id = account['id']
33
+ registration = create_registration 'learning_instance_id' => learning_instance_id,
34
+ 'account_id' => account_id,
35
+ 'type' => options.fetch('type', 'learner')
36
+ {
37
+ 'external_user_id' => external_user_id,
38
+ 'registration_id' => registration['id'],
39
+ 'account_id' => account_id,
40
+ }
41
+ end
42
+
43
+ def get_registration id
44
+ Log.info "Getting a registration " + id
45
+ kapi.get "/v0/registrations/#{id}"
46
+ end
47
+
48
+ def delete_registration id
49
+ Log.info "Deleting a registration " + id
50
+ kapi.delete "/v0/registrations/#{id}"
51
+ end
52
+
53
+ def get_registrations_for_account account_id
54
+ Log.info "Getting a registration for account " + account_id
55
+ kapi.get "/v0/accounts/#{account_id}/registrations"
56
+ end
57
+
58
+
59
+ ##GOAL ACTIVATATION STUFF
60
+ def activate_registration_on_goal learning_instance_id, registration_id, goal_id
61
+ Log.info "Activating a goal for a registration"
62
+ kapi.put "/v0/learning-instances/#{learning_instance_id}/goals/#{goal_id}/registrations/#{registration_id}", {}
63
+ end
64
+
65
+ def deactivate_registration_on_goal learning_instance_id, registration_id, goal_id
66
+ Log.info "Deactivating a goal for a registration"
67
+ kapi.delete "/v0/learning-instances/#{learning_instance_id}/goals/#{goal_id}/registrations/#{registration_id}"
68
+ end
69
+
70
+ def list_activated_registrations learning_instance_id, goal_id
71
+ Log.info "Listing activated registrations for a goal"
72
+ end
73
+
74
+ def check_if_activated learning_instance_id, registration_id, goal_id
75
+ Log.info "Checking if a specific registration is activated for a specific goal"
76
+ kapi.get "/v0/learning-instances/#{learning_instance_id}/goals/#{goal_id}/registrations/#{registration_id}"
77
+ return true
78
+ rescue Grifter::RequestException => e
79
+ if e.code == 404
80
+ return false
81
+ else
82
+ raise e
83
+ end
84
+ end
85
+
86
+
87
+ ##SENDING IN EVENTS STUFF
88
+ def send_recommendation_followed registration_id, module_id, overrides={}
89
+ Log.info "Sending a recommendation followed event"
90
+ kapi.post "/v0/registrations/#{registration_id}/recommendation-followed-events", {
91
+ 'module_id' => module_id,
92
+ 'time_followed' => datetime,
93
+ 'recommendation_id' => 987654,
94
+ }.merge(overrides)
95
+ end
96
+
97
+ def send_graded_event registration_id, module_id, overrides={}
98
+ Log.info "Sending a graded event"
99
+ kapi.post "/v0/registrations/#{registration_id}/graded-events", {
100
+ 'response' => "sample of a response",
101
+ 'duration' => 4321,
102
+ 'module_id' => module_id,
103
+ 'interaction_end_time' => datetime,
104
+ 'score' => 0.99,
105
+ 'is_correct' => true,
106
+ 'is_complete' => true,
107
+ }.merge(overrides)
108
+ end
109
+
110
+ def send_ungraded_event registration_id, module_id, overrides={}
111
+ Log.info "Sending an ungraded event"
112
+ kapi.post "/v0/registrations/#{registration_id}/ungraded-events", {
113
+ 'duration' => 876543,
114
+ 'module_id' => module_id,
115
+ 'is_complete' => true,
116
+ 'interaction_end_time' => datetime,
117
+ }.merge(overrides)
118
+ end
119
+
120
+ def send_focus_event registration_id, goal_id, overrides={}
121
+ Log.info "Sending a focus event"
122
+ kapi.post "/v0/registrations/#{registration_id}/focus-events", {
123
+ 'goal_id' => goal_id,
124
+ }.merge(overrides)
125
+ end
126
+
127
+ def send_random_event_on_graph registration_id, graph
128
+ atom_id = find_random_atom_id graph
129
+ send_correct_event_type_for_atom registration_id, atom_id, graph
130
+ end
131
+
132
+ def send_correct_event_type_for_atom registration_id, atom_id, graph
133
+ content_types = get_content_types graph, atom_id
134
+
135
+ if content_types.include? 'assesssment'
136
+ correct = [true, false].sample
137
+ send_graded_event registration_id, atom_id, is_correct: correct
138
+ else
139
+ send_ungraded_event registration_id, atom_id
140
+ end
141
+ end
142
+
143
+ ## GETTING RECOMMENDATION STUFF
144
+ def get_recommendation registration_id, goal_id=nil, continued_recommendations=nil
145
+ goal_id = random_uuid unless goal_id #this only works in local mode, considering removing it
146
+ Log.info "Getting a recommendation for registration: " + registration_id + " goal: " + goal_id
147
+ query_params= { 'goal_id' => goal_id }
148
+ query_params['continued_recommendations'] = continued_recommendations if continued_recommendations
149
+ query_string = URI.encode_www_form(query_params)
150
+ kapi.get "/v0/registrations/#{registration_id}/recommendation?#{query_string}"
151
+ end
152
+
153
+ def send_batch_events registration_id, events, overrides={}
154
+ Log.info "Sending a batch of student events"
155
+ kapi.post "/v0/registrations/#{registration_id}/batch-events", {
156
+ 'goal_id' => nil,
157
+ 'events' => events
158
+ }.merge(overrides)
159
+ end