bearcat 1.0.0 → 1.5.24

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 (193) hide show
  1. checksums.yaml +7 -0
  2. data/bearcat.gemspec +15 -5
  3. data/lib/badgrcat/api_array.rb +25 -0
  4. data/lib/badgrcat/client/methods.rb +54 -0
  5. data/lib/badgrcat/client.rb +53 -0
  6. data/lib/badgrcat/version.rb +3 -0
  7. data/lib/bearcat/api_array.rb +132 -65
  8. data/lib/bearcat/client/account_reports.rb +6 -14
  9. data/lib/bearcat/client/accounts.rb +18 -6
  10. data/lib/bearcat/client/analytics.rb +12 -0
  11. data/lib/bearcat/client/assignment_groups.rb +15 -0
  12. data/lib/bearcat/client/assignments.rb +17 -9
  13. data/lib/bearcat/client/blueprint_courses.rb +25 -0
  14. data/lib/bearcat/client/calendar_events.rb +9 -17
  15. data/lib/bearcat/client/canvas_files.rb +0 -2
  16. data/lib/bearcat/client/conferences.rb +3 -8
  17. data/lib/bearcat/client/content_exports.rb +39 -0
  18. data/lib/bearcat/client/content_migrations.rb +54 -0
  19. data/lib/bearcat/client/conversations.rb +3 -8
  20. data/lib/bearcat/client/courses.rb +25 -14
  21. data/lib/bearcat/client/custom_gradebook_columns.rb +21 -0
  22. data/lib/bearcat/client/discussions.rb +10 -4
  23. data/lib/bearcat/client/enrollments.rb +9 -25
  24. data/lib/bearcat/client/external_tools.rb +18 -0
  25. data/lib/bearcat/client/file_helper.rb +36 -30
  26. data/lib/bearcat/client/files.rb +9 -0
  27. data/lib/bearcat/client/folders.rb +24 -0
  28. data/lib/bearcat/client/graph_ql.rb +17 -0
  29. data/lib/bearcat/client/group_categories.rb +18 -0
  30. data/lib/bearcat/client/group_memberships.rb +14 -0
  31. data/lib/bearcat/client/groups.rb +10 -2
  32. data/lib/bearcat/client/learning_outcomes.rb +17 -0
  33. data/lib/bearcat/client/logins.rb +20 -0
  34. data/lib/bearcat/client/module_items.rb +18 -0
  35. data/lib/bearcat/client/modules.rb +12 -7
  36. data/lib/bearcat/client/o_auth2.rb +18 -9
  37. data/lib/bearcat/client/outcome_groups.rb +2 -4
  38. data/lib/bearcat/client/outcome_imports.rb +48 -0
  39. data/lib/bearcat/client/outcomes.rb +4 -7
  40. data/lib/bearcat/client/pages.rb +15 -0
  41. data/lib/bearcat/client/progresses.rb +9 -0
  42. data/lib/bearcat/client/quizzes.rb +13 -9
  43. data/lib/bearcat/client/reports.rb +37 -17
  44. data/lib/bearcat/client/roles.rb +15 -0
  45. data/lib/bearcat/client/rubric.rb +17 -0
  46. data/lib/bearcat/client/rubric_assessment.rb +13 -0
  47. data/lib/bearcat/client/rubric_association.rb +13 -0
  48. data/lib/bearcat/client/search.rb +9 -0
  49. data/lib/bearcat/client/sections.rb +10 -17
  50. data/lib/bearcat/client/sis_imports.rb +6 -12
  51. data/lib/bearcat/client/submissions.rb +53 -21
  52. data/lib/bearcat/client/tabs.rb +12 -0
  53. data/lib/bearcat/client/users.rb +32 -13
  54. data/lib/bearcat/client.rb +111 -45
  55. data/lib/bearcat/client_module.rb +103 -0
  56. data/lib/bearcat/rate_limiting/increment_bucket.lua +33 -0
  57. data/lib/bearcat/rate_limiting/redis_script.rb +164 -0
  58. data/lib/bearcat/rate_limiting.rb +69 -0
  59. data/lib/bearcat/redis_connection.rb +106 -0
  60. data/lib/bearcat/spec_helpers.rb +125 -0
  61. data/lib/bearcat/version.rb +1 -1
  62. data/lib/bearcat.rb +49 -0
  63. data/lib/catalogcat/api_array.rb +22 -0
  64. data/lib/catalogcat/client/catalogs.rb +21 -0
  65. data/lib/catalogcat/client/certificates.rb +17 -0
  66. data/lib/catalogcat/client/courses.rb +25 -0
  67. data/lib/catalogcat/client/email_domain_sets.rb +17 -0
  68. data/lib/catalogcat/client/enrollments.rb +25 -0
  69. data/lib/catalogcat/client/orders.rb +13 -0
  70. data/lib/catalogcat/client/user_registrations.rb +9 -0
  71. data/lib/catalogcat/client.rb +26 -0
  72. data/lib/catalogcat/version.rb +3 -0
  73. data/lib/catalogcat.rb +14 -0
  74. data/spec/bearcat/api_array_spec.rb +112 -0
  75. data/spec/bearcat/client/accounts_spec.rb +71 -1
  76. data/spec/bearcat/client/analytics_spec.rb +22 -0
  77. data/spec/bearcat/client/assignment_groups_spec.rb +47 -0
  78. data/spec/bearcat/client/assignments_spec.rb +43 -0
  79. data/spec/bearcat/client/blueprint_courses_spec.rb +43 -0
  80. data/spec/bearcat/client/canvas_files_spec.rb +1 -2
  81. data/spec/bearcat/client/content_exports_spec.rb +68 -0
  82. data/spec/bearcat/client/content_migrations_spec.rb +94 -0
  83. data/spec/bearcat/client/courses_spec.rb +81 -2
  84. data/spec/bearcat/client/custom_gradebook_columns_spec.rb +66 -0
  85. data/spec/bearcat/client/discussions_spec.rb +73 -0
  86. data/spec/bearcat/client/enrollments_spec.rb +10 -0
  87. data/spec/bearcat/client/external_tools_spec.rb +106 -0
  88. data/spec/bearcat/client/files_spec.rb +15 -0
  89. data/spec/bearcat/client/folders_spec.rb +18 -0
  90. data/spec/bearcat/client/graph_ql_spec.rb +35 -0
  91. data/spec/bearcat/client/group_categories_spec.rb +45 -0
  92. data/spec/bearcat/client/group_membership_spec.rb +14 -0
  93. data/spec/bearcat/client/group_memberships_spec.rb +36 -0
  94. data/spec/bearcat/client/groups_spec.rb +46 -0
  95. data/spec/bearcat/client/learning_outcomes_spec.rb +25 -0
  96. data/spec/bearcat/client/module_items_spec.rb +60 -0
  97. data/spec/bearcat/client/modules_spec.rb +38 -1
  98. data/spec/bearcat/client/o_auth2_spec.rb +3 -3
  99. data/spec/bearcat/client/pages_spec.rb +17 -0
  100. data/spec/bearcat/client/quizzes_spec.rb +41 -4
  101. data/spec/bearcat/client/reports_spec.rb +40 -1
  102. data/spec/bearcat/client/roles_spec.rb +24 -0
  103. data/spec/bearcat/client/rubric_assessment_spec.rb +47 -0
  104. data/spec/bearcat/client/rubric_association_spec.rb +39 -0
  105. data/spec/bearcat/client/rubric_spec.rb +45 -0
  106. data/spec/bearcat/client/search_spec.rb +16 -0
  107. data/spec/bearcat/client/sections_spec.rb +12 -0
  108. data/spec/bearcat/client/submissions_spec.rb +47 -2
  109. data/spec/bearcat/client/users_spec.rb +43 -0
  110. data/spec/bearcat/client_spec.rb +1 -4
  111. data/spec/bearcat/rate_limiting_spec.rb +62 -0
  112. data/spec/bearcat/stub_bearcat_spec.rb +15 -0
  113. data/spec/fixtures/access_token.json +3 -0
  114. data/spec/fixtures/account_admin_create.json +14 -0
  115. data/spec/fixtures/account_admin_delete.json +15 -0
  116. data/spec/fixtures/account_admins.json +54 -0
  117. data/spec/fixtures/account_courses.json +48 -0
  118. data/spec/fixtures/account_grading_standards.json +20 -0
  119. data/spec/fixtures/account_groups.json +42 -0
  120. data/spec/fixtures/account_role.json +34 -0
  121. data/spec/fixtures/account_roles.json +35 -0
  122. data/spec/fixtures/account_sis_imports.json +39 -0
  123. data/spec/fixtures/account_sub_accounts.json +17 -0
  124. data/spec/fixtures/accounts.json +13 -0
  125. data/spec/fixtures/assignment.json +32 -0
  126. data/spec/fixtures/assignment_group.json +7 -0
  127. data/spec/fixtures/assignment_groups.json +16 -0
  128. data/spec/fixtures/blueprint_migration.json +12 -0
  129. data/spec/fixtures/blueprint_subscriptions.json +5 -0
  130. data/spec/fixtures/blueprint_template.json +7 -0
  131. data/spec/fixtures/blueprint_update_assocations_success.json +3 -0
  132. data/spec/fixtures/communication_channels.json +10 -0
  133. data/spec/fixtures/content_export.json +9 -0
  134. data/spec/fixtures/content_migration_files/content_migration.json +13 -0
  135. data/spec/fixtures/course_copy.json +18 -0
  136. data/spec/fixtures/course_files.json +38 -0
  137. data/spec/fixtures/course_folder.json +21 -0
  138. data/spec/fixtures/course_folders.json +44 -0
  139. data/spec/fixtures/course_grading_standards.json +20 -0
  140. data/spec/fixtures/course_settings.json +33 -0
  141. data/spec/fixtures/create_course_discussion.json +44 -0
  142. data/spec/fixtures/created_group.json +37 -0
  143. data/spec/fixtures/created_group_category.json +15 -0
  144. data/spec/fixtures/created_group_membership.json +8 -0
  145. data/spec/fixtures/created_module.json +13 -0
  146. data/spec/fixtures/custom_gradebook_columns/column_data.json +4 -0
  147. data/spec/fixtures/custom_gradebook_columns/custom_gradebook_column.json +7 -0
  148. data/spec/fixtures/custom_gradebook_columns/custom_gradebook_columns.json +16 -0
  149. data/spec/fixtures/custom_gradebook_columns/gradebook_column_progress.json +14 -0
  150. data/spec/fixtures/dashboard.json +6 -0
  151. data/spec/fixtures/delete_course.json +3 -0
  152. data/spec/fixtures/delete_group_category.json +3 -0
  153. data/spec/fixtures/deleted_group.json +37 -0
  154. data/spec/fixtures/department_level_participation.json +73 -0
  155. data/spec/fixtures/department_level_statistics.json +10 -0
  156. data/spec/fixtures/discussion_entries.json +21 -0
  157. data/spec/fixtures/discussion_entry_replies.json +21 -0
  158. data/spec/fixtures/discussion_topic.json +49 -0
  159. data/spec/fixtures/discussion_topics.json +51 -0
  160. data/spec/fixtures/edited_group.json +129 -0
  161. data/spec/fixtures/edited_group_category.json +15 -0
  162. data/spec/fixtures/enrollment_terms.json +1 -1
  163. data/spec/fixtures/external_tool.json +55 -0
  164. data/spec/fixtures/external_tools.json +57 -0
  165. data/spec/fixtures/file.csv +5 -0
  166. data/spec/fixtures/gradebook_history.json +52 -0
  167. data/spec/fixtures/graph_ql_scores.json +33 -0
  168. data/spec/fixtures/group.json +15 -0
  169. data/spec/fixtures/group_categories.json +28 -0
  170. data/spec/fixtures/group_category.json +13 -0
  171. data/spec/fixtures/group_category_groups.json +20 -0
  172. data/spec/fixtures/group_membership.json +7 -0
  173. data/spec/fixtures/learning_outcome.json +32 -0
  174. data/spec/fixtures/merge_user.json +8 -0
  175. data/spec/fixtures/module.json +15 -0
  176. data/spec/fixtures/module_item.json +15 -0
  177. data/spec/fixtures/module_items.json +47 -0
  178. data/spec/fixtures/ok.json +3 -0
  179. data/spec/fixtures/outcome_result.json +13 -0
  180. data/spec/fixtures/pages.json +40 -0
  181. data/spec/fixtures/progress.json +13 -0
  182. data/spec/fixtures/quizzes/course_quiz_questions.json +59 -0
  183. data/spec/fixtures/quizzes/quiz_assignment_override.json +31 -0
  184. data/spec/fixtures/reactivate_enrollment.json +20 -0
  185. data/spec/fixtures/rubric.json +13 -0
  186. data/spec/fixtures/rubric_assessment.json +32 -0
  187. data/spec/fixtures/rubric_association.json +13 -0
  188. data/spec/fixtures/search_find_recipients.json +10 -0
  189. data/spec/fixtures/update_section.json +1 -1
  190. data/spec/fixtures/user_details.json +16 -0
  191. data/spec/fixtures/user_logins.json +9 -0
  192. data/spec/helper.rb +2 -0
  193. metadata +336 -43
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8dfc188f90b9e9ecbb6dca39381af0881c04279c2e28a51dc37155e396411589
4
+ data.tar.gz: e315e2df134089927326d0a36654fee28b01d85c8c556c1dfe33992e4c5a9924
5
+ SHA512:
6
+ metadata.gz: 40722c095a27ed44dbd42e9a0152a4791d6f8d3e3e045762085f59fc0dba02cc487ba43f534cccc4d703a6a85cb1b6ad4e1ca32c45205a0c579589b65dfb4047
7
+ data.tar.gz: a0593f571e593bfe1faa313ccc4692900e693377a31d8c292f44dca68d0141ea0411554b3232dbb48aa06d52f9a2cc4730135188e99b7eef0ce632b93495722b
data/bearcat.gemspec CHANGED
@@ -2,27 +2,37 @@
2
2
  # spec/fixtures/bearcat.jpg Attribution: TassiloRau at the German language Wikipedia
3
3
  lib = File.expand_path('../lib', __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'bearcat/version'
5
+
6
+ begin
7
+ require 'bearcat/version'
8
+ version = Bearcat::VERSION
9
+ rescue LoadError
10
+ version = "0.0.0.docker"
11
+ end
6
12
 
7
13
  Gem::Specification.new do |gem|
8
- gem.authors = ["Nathan Mills, Jake Sorce"]
9
- gem.email = ["nathanm@instructure.com, jake@instructure.com"]
14
+ gem.authors = ["Instructure CustomDev"]
15
+ gem.email = ["pseng@instructure.com"]
10
16
  gem.description = %q{Ruby interface for interacting with the canvas API}
11
17
  gem.summary = %q{Canvas API}
12
18
 
13
19
  gem.files = %w[Rakefile bearcat.gemspec]
14
- gem.files += Dir.glob("lib/**/*.rb")
20
+ gem.files += Dir.glob("lib/**/*")
15
21
  gem.files += Dir.glob("spec/**/*")
16
22
  gem.test_files = Dir.glob("spec/**/*")
17
23
  gem.name = "bearcat"
18
24
  gem.require_paths = ["lib"]
19
- gem.version = Bearcat::VERSION
25
+ gem.version = version
20
26
 
21
27
  gem.add_development_dependency "rake"
22
28
  gem.add_development_dependency "bundler", ">= 1.0.0"
23
29
  gem.add_development_dependency "rspec", "~> 2.6"
24
30
  gem.add_development_dependency "webmock"
25
31
  gem.add_development_dependency 'pry'
32
+ gem.add_development_dependency 'sidekiq', "< 7.0"
26
33
 
34
+ gem.add_dependency "activesupport"
27
35
  gem.add_dependency "footrest", ">= 0.2.2"
36
+ gem.add_dependency "connection_pool", ">= 2.2.0", "< 3.0"
37
+ gem.add_dependency "ffi", "~> 1.16.3"
28
38
  end
@@ -0,0 +1,25 @@
1
+ require 'bearcat/api_array'
2
+
3
+ module Badgrcat
4
+ class ApiArray < Bearcat::ApiArray
5
+ def [](key)
6
+ if key.is_a?(Numeric)
7
+ super
8
+ else
9
+ @raw_response.body[key]
10
+ end
11
+ end
12
+
13
+ def status
14
+ self["status"]
15
+ end
16
+
17
+ def self.array_key(response)
18
+ if response.body.is_a?(Hash) && response.body.key?("result")
19
+ "result"
20
+ else
21
+ nil
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ module Badgrcat
2
+ class Client < Footrest::Client
3
+ module Methods
4
+ extend Bearcat::Client::ClientModule
5
+
6
+ prefix "/v2/issuers" do
7
+ get :issuers
8
+ post :create_issuer
9
+
10
+ prefix "/:issuer" do
11
+ get :issuer
12
+ put :update_issuer
13
+ delete :delete_issuer
14
+
15
+ prefix "/assertions" do
16
+ get :issuer_assertions
17
+ post :create_issuer_assertion
18
+ end
19
+
20
+ prefix "/badgeclasses" do
21
+ get :issuer_badgeclasses
22
+ post :create_issuer_badgeclass
23
+ end
24
+ end
25
+ end
26
+
27
+ prefix "/v2/badgeclasses" do
28
+ get :badgeclasses
29
+ post :create_badgeclass
30
+
31
+ prefix "/:badgeclass" do
32
+ get :badgeclass
33
+ put :update_badgeclass
34
+ delete :delete_badgeclass
35
+
36
+ prefix "/assertions" do
37
+ get :badgeclass_assertions
38
+ post :create_badgeclass_assertion
39
+ end
40
+ end
41
+ end
42
+
43
+ prefix "/v2/assertions" do
44
+ post :revoke_assertions, "/revoke"
45
+
46
+ prefix "/v2/assertions/:assertion" do
47
+ get :assertion
48
+ put :update_assertion
49
+ delete :delete_assertion
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,53 @@
1
+ require 'footrest/client'
2
+
3
+ module Badgrcat
4
+ class Client < Footrest::Client
5
+ require 'badgrcat/api_array' # monkey patch
6
+
7
+ Dir[File.join(__dir__, 'client', '*.rb')].each do |mod|
8
+ mname = File.basename(mod, '.*').camelize
9
+ require mod
10
+ include "Badgrcat::Client::#{mname}".constantize
11
+ end
12
+
13
+ # Override Footrest request for ApiArray support
14
+ def request(method, &block)
15
+ begin
16
+ response = connection.send(method, &block)
17
+ rescue Footrest::HttpError::Unauthorized
18
+ # Reauthenticate and retry
19
+ authenticate!
20
+ response = connection.send(method, &block)
21
+ end
22
+
23
+ Badgrcat::ApiArray.process_response(response, self)
24
+ end
25
+
26
+ def authenticate!
27
+ connection.headers[:authorization] = nil
28
+
29
+ tok_params = {
30
+ scope: config[:scope],
31
+ client_id: config[:client_id],
32
+ }
33
+
34
+ if @refresh_token
35
+ tok_params.merge!({
36
+ grant_type: "refresh_token",
37
+ refresh_token: @refresh_token,
38
+ })
39
+ else
40
+ tok_params.merge!({
41
+ username: config[:username],
42
+ password: config[:password],
43
+ })
44
+ end
45
+
46
+ authresp = connection.send(:post, "o/token", tok_params)
47
+ authdata = authresp.body
48
+
49
+ @refresh_token = authdata["refresh_token"].presence || @refresh_token
50
+ connection.headers[:authorization] = "#{authdata['token_type']} #{authdata['access_token']}"
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Badgrcat
2
+ VERSION = 'bearcat' unless defined?(Badgrcat::VERSION)
3
+ end
@@ -1,35 +1,56 @@
1
+ require 'active_support/core_ext/module'
2
+
1
3
  module Bearcat
2
4
  class ApiArray
3
5
  include Enumerable
4
6
 
5
- attr_reader :status, :headers, :members
7
+ attr_reader :raw_response, :members
6
8
 
7
9
  def self.process_response(response, api_client)
8
10
  if response.body.is_a?(Array)
9
- ApiArray.new(response, api_client)
11
+ self.new(response, api_client)
10
12
  elsif key = array_key(response)
11
- ApiArray.new(response, api_client, key)
13
+ self.new(response, api_client, key)
14
+ else
15
+ make_indifferent(response.body)
16
+ end
17
+ end
18
+
19
+ def self.make_indifferent(thing)
20
+ if thing.is_a?(Array)
21
+ thing.map { |v| make_indifferent(v) }
22
+ elsif thing.is_a?(Hash)
23
+ thing.with_indifferent_access
12
24
  else
13
- response.body
25
+ thing
14
26
  end
15
27
  end
16
28
 
17
29
  def initialize(response, api_client, array_key = nil)
18
30
  @api_client = api_client
31
+ @raw_response = response
19
32
  @array_key = array_key
20
- @page_count = 100
33
+ @page_count = nil
34
+
21
35
  case response.status
22
- when 200..206
23
- @members = process_body(response)
24
- @status = response.status
25
- @headers = response.headers
26
- @method = response.env[:method]
27
- init_pages(@headers['Link'])
36
+ when 200..206
37
+ @members = process_body(response)
38
+ init_pages
28
39
  end
29
40
  end
30
41
 
31
- def [](i)
32
- @members[i]
42
+ delegate :status, :headers, to: :raw_response
43
+
44
+ def method
45
+ raw_response.env[:method]
46
+ end
47
+
48
+ def [](key)
49
+ if key.is_a?(Numeric)
50
+ @members[key]
51
+ else
52
+ @raw_response.body[key]
53
+ end
33
54
  end
34
55
 
35
56
  def last
@@ -44,64 +65,61 @@ module Bearcat
44
65
  @link_hash['next'] || @link_hash['prev']
45
66
  end
46
67
 
47
- def next_page
48
- load_page('next')
49
- end
68
+ def page_count
69
+ return nil unless @link_hash['last']
50
70
 
51
- def prev_page
52
- load_page('prev')
71
+ uri = URI.parse(@link_hash['last'])
72
+ params = CGI.parse(uri.query)
73
+ params.dig('page', 0)&.to_i || 1
53
74
  end
54
75
 
55
- def first_page
56
- load_page('first')
76
+ %w[next prev first last].each do |rel|
77
+ define_method :"#{rel}_page" do
78
+ load_page(rel)
79
+ end
57
80
  end
58
81
 
59
- def last_page
60
- load_page('last')
61
- end
82
+ def each_page(page_count = nil, &block)
83
+ return to_enum(:each_page, page_count) unless block_given?
62
84
 
63
- def each_page(page_count = 50, &block)
64
- @page_count = page_count
65
- block.call(@members)
66
- while @link_hash['next']
67
- response = get_page(@link_hash['next'])
68
- @headers = response.headers
69
- @status = response.status
70
- @method = response.env[:method]
71
- @members = process_body(response)
72
- init_pages(@headers[:link])
85
+ if pages?
86
+ iterate_pages(page_count) do |page_response|
87
+ @members = process_body(page_response)
88
+ break unless @members.present?
89
+ block.call(@members)
90
+ end
91
+ else
73
92
  block.call(@members)
74
93
  end
75
- @link_hash = {}
76
94
  end
77
95
 
78
- def all_pages!(page_count = 50)
96
+ def all_pages_each(page_count = nil, &block)
97
+ return to_enum(:all_pages_each, page_count) unless block_given?
98
+
99
+ each_page(page_count) do |page|
100
+ page.each &block
101
+ end
102
+ end
103
+
104
+ def all_pages!(page_count = nil)
79
105
  if pages?
80
- @page_count = page_count
81
- response = get_page(@link_hash['first'])
82
- @headers = response.headers
83
- @status = response.status
84
- @method = response.env[:method]
85
- init_pages(@headers[:link])
86
- @members = process_body(response)
87
- while @link_hash['next']
88
- response = get_page(@link_hash['next'])
89
- @headers = response.headers
90
- @status = response.status
91
- @method = response.env[:method]
92
- @members.concat(process_body(response))
93
- init_pages(@headers[:link])
106
+ @members = []
107
+ iterate_pages(page_count) do |page_response|
108
+ page_members = process_body(page_response)
109
+ break unless page_members.present?
110
+ @members.concat(page_members)
94
111
  end
95
112
  @link_hash = {}
96
113
  end
97
114
  self
98
115
  end
99
116
 
100
- private
117
+ protected
101
118
 
102
- def init_pages(link_header)
119
+ def init_pages(link_header = headers[:link])
103
120
  @link_hash = {}
104
- if @headers.has_key? 'Link'
121
+ if headers.has_key? 'Link'
122
+
105
123
  links = link_header.split(/,\s?/)
106
124
 
107
125
  links.each do |link|
@@ -113,12 +131,16 @@ module Bearcat
113
131
  end
114
132
  end
115
133
 
116
- def get_page(url, params = {})
117
- params['per_page'] = @page_count unless params.has_key? 'per_page' || !@page_count
118
- query = URI.parse(url).query
119
- p = CGI.parse(query).merge(params)
120
- u = url.gsub("?#{query}", '')
121
- p.each { |k, v| p[k] = v.first if v.is_a?(Array) }
134
+ def get_page(url, params = {}, page_size_param: 'per_page')
135
+ params[page_size_param] = @page_count unless params.key?(page_size_param) || !@page_count
136
+
137
+ parsed_url = URI.parse(url)
138
+ p = parse_url_params(parsed_url)
139
+ u = url.gsub("?#{parsed_url.query}", '')
140
+
141
+ # merge params
142
+ p.merge!(params)
143
+
122
144
  @api_client.connection.send(:get) do |r|
123
145
  r.url(u, p)
124
146
  end
@@ -127,10 +149,48 @@ module Bearcat
127
149
  def load_page(rel)
128
150
  if @link_hash.has_key? rel
129
151
  response = get_page(@link_hash[rel])
130
- ApiArray.process_response(response, @api_client)
152
+ self.class.process_response(response, @api_client)
153
+ end
154
+ end
155
+
156
+ def iterate_pages(per_page = @page_count)
157
+ return to_enum(:iterate_pages, per_page) unless block_given?
158
+
159
+ if per_page.present? && per_page != per_page_count && @link_hash['first']
160
+ @page_count = per_page
161
+ @raw_response = response = get_page(@link_hash['first'])
162
+ yield response
163
+ init_pages
164
+ else
165
+ yield @raw_response
166
+ end
167
+
168
+ while @link_hash['next']
169
+ @raw_response = response = get_page(@link_hash['next'])
170
+ yield response
171
+ init_pages
131
172
  end
132
173
  end
133
174
 
175
+ def per_page_count
176
+ url = raw_response.env[:url]
177
+ query_params = parse_url_params(url)
178
+ query_params[:per_page]&.to_i
179
+ end
180
+
181
+ def parse_url_params(url)
182
+ url = URI.parse(url) if url.is_a?(String)
183
+ p = CGI.parse(url.query || '')
184
+ p.default = nil
185
+
186
+ # strip value out of array if value is an array and key doesn't have [] (parameter is not an array parameter)
187
+ p.each { |k, v| p[k] = v.first if v.is_a?(Array) && k !~ /\[\]$/ }
188
+ # remove [] from key names, this is copied from rails' {}.transform_keys!
189
+ p.keys.each { |k| p[k.delete('[]')] = p.delete(k) }
190
+
191
+ p.with_indifferent_access
192
+ end
193
+
134
194
  #TODO: This is a quick fix for JSONAPI responses if we need to do this for anything else we need to do this a better way
135
195
  def self.array_key(response)
136
196
  key = nil
@@ -138,7 +198,7 @@ module Bearcat
138
198
  path = response.env[:url].path
139
199
  if path.match(/.*\/(courses||groups)\/\d+\/conferences/)
140
200
  key = 'conferences'
141
- elsif path.match(/.*\/accounts\/d+\/terms/)
201
+ elsif path.match(/.*\/accounts\/(?:(?:\d+~)?\d+|self)\/terms/)
142
202
  key = 'enrollment_terms'
143
203
  end
144
204
  end
@@ -146,12 +206,19 @@ module Bearcat
146
206
  end
147
207
 
148
208
  def process_body(response)
149
- if response.body.is_a?(Array)
150
- response.body
151
- elsif response.body.is_a?(Hash) && @array_key
152
- response.body[@array_key]
209
+ data = response.body
210
+ if @array_key.is_a?(Proc)
211
+ data = @array_key.call(data, response)
212
+ elsif @array_key.present?
213
+ ak = @array_key
214
+ ak = ak.split('.') if ak.is_a?(String)
215
+ ak = Array(ak)
216
+ data = data.dig(*ak)
153
217
  end
154
- end
155
218
 
219
+ raise "Response could not be mapped to items" unless data.is_a?(Array)
220
+
221
+ self.class.make_indifferent(data)
222
+ end
156
223
  end
157
224
  end
@@ -1,21 +1,13 @@
1
1
  module Bearcat
2
2
  class Client
3
3
  module AccountReports
4
+ extend ClientModule
4
5
 
5
- def available_reports(account, params={})
6
- get("/api/v1/accounts/#{account}/reports", params)
7
- end
8
-
9
- def start_report(account, report, params)
10
- post("api/v1/accounts/#{account}/reports/#{report}", params)
11
- end
12
-
13
- def report_index(account, report, params={})
14
- get("/api/v1/accounts/#{account}/reports/#{report}", params)
15
- end
16
-
17
- def report_status(account, report, report_id)
18
- get("/api/v1/accounts/#{account}/reports/#{report}/#{report_id}")
6
+ prefix "/api/v1/accounts/:account/reports/" do
7
+ get :available_reports
8
+ post :start_report, ":report"
9
+ get :report_index, ":report"
10
+ get :report_status, ":report/:report_id"
19
11
  end
20
12
  end
21
13
  end
@@ -1,15 +1,27 @@
1
1
  module Bearcat
2
2
  class Client < Footrest::Client
3
3
  module Accounts
4
+ extend ClientModule
4
5
 
5
- def account(account)
6
- get("/api/v1/accounts/#{account}")
7
- end
6
+ prefix "/api/v1/accounts/" do
7
+ get :list_accounts
8
8
 
9
- def terms(account, params = {})
10
- get("/api/v1/accounts/#{account}/terms")
9
+ prefix ":account/" do
10
+ get :account
11
+ get :list_sub_accounts, "sub_accounts"
12
+ get :terms, "terms"
13
+ get :account_admins, "admins"
14
+ post :create_account_admin, "admins"
15
+ delete :delete_account_admin, "admins/:user"
16
+ get :list_roles, "roles"
17
+ get :account_roles, "roles"
18
+ get :account_courses, "courses"
19
+ get :account_grading_standards, "grading_standards"
20
+ get :account_grading_standard, "grading_standards/:grading_standard_id"
21
+ get :account_sis_imports, "sis_imports"
22
+ get :enrollment, "enrollments/:enrollment"
23
+ end
11
24
  end
12
-
13
25
  end
14
26
  end
15
27
  end
@@ -0,0 +1,12 @@
1
+ module Bearcat
2
+ class Client < Footrest::Client
3
+ module Analytics
4
+ extend ClientModule
5
+
6
+ prefix "/api/v1/accounts/:account/analytics/terms/:term/" do
7
+ get :department_level_participation, "activity"
8
+ get :department_level_statistics, "statistics"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module Bearcat
2
+ class Client < Footrest::Client
3
+ module AssignmentGroups
4
+ extend ClientModule
5
+
6
+ prefix "/api/v1/courses/:course/assignment_groups/" do
7
+ get :list_assignment_groups
8
+ post :create_assignment_group
9
+ get :assignment_group, ":assignment_group_id"
10
+ put :update_assignment_group, ":assignment_group_id"
11
+ delete :delete_assignment_group, ":assignment_group_id"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,18 +1,26 @@
1
1
  module Bearcat
2
2
  class Client < Footrest::Client
3
3
  module Assignments
4
+ extend ClientModule
4
5
 
5
- def assignments(course, params={})
6
- get("/api/v1/courses/#{course}/assignments", params)
7
- end
6
+ prefix "/api/v1/courses/:course/assignments/" do
7
+ get :assignments, ""
8
+ post :create_assignment, ""
8
9
 
9
- def create_assignment_override(course, assignment, params)
10
- post("api/v1/courses/#{course}/assignments/#{assignment}/overrides", params)
11
- end
10
+ get :all_assignment_overrides, "overrides"
11
+ post :batch_create_assignment_overrides, "overrides"
12
+ put :batch_update_assignment_overrides, "overrides"
13
+
14
+ prefix ":assignment/" do
15
+ get :assignment
16
+ put :edit_assignment
17
+ delete :delete_assignment
12
18
 
13
- def create_assignment(course, params={})
14
- post("/api/v1/courses/#{course}/assignments", params)
19
+ get :assignment_overrides, "overrides"
20
+ post :create_assignment_override, "overrides"
21
+ delete :delete_assignment_override, "overrides/:override"
22
+ end
15
23
  end
16
24
  end
17
25
  end
18
- end
26
+ end
@@ -0,0 +1,25 @@
1
+ module Bearcat
2
+ class Client < Footrest::Client
3
+ module BlueprintCourses
4
+ extend ClientModule
5
+
6
+ prefix "/api/v1/courses/:course/" do
7
+ # Get blueprint information
8
+ # https://canvas.instructure.com/doc/api/blueprint_courses.html#method.master_courses/master_templates.show
9
+ get :blueprint_template, "blueprint_templates/:template_id", defaults: { template_id: 'default' }
10
+
11
+ # List blueprint subscriptions
12
+ # https://canvas.instructure.com/doc/api/blueprint_courses.html#method.master_courses/master_templates.subscriptions_index
13
+ get :blueprint_subscriptions, "blueprint_subscriptions"
14
+
15
+ # Update associated courses
16
+ # https://canvas.instructure.com/doc/api/blueprint_courses.html#method.master_courses/master_templates.update_associations
17
+ put :blueprint_update_associations, "blueprint_templates/:template_id/update_associations", defaults: { template_id: 'default' }
18
+
19
+ # Begin a migration to push to associated courses
20
+ # https://canvas.instructure.com/doc/api/blueprint_courses.html#method.master_courses/master_templates.queue_migration
21
+ post :start_blueprint_migration, "blueprint_templates/:template_id/migrations", defaults: { template_id: 'default' }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,25 +1,17 @@
1
1
  module Bearcat
2
2
  class Client < Footrest::Client
3
3
  module CalendarEvents
4
+ extend ClientModule
4
5
 
5
- def calendar_events(params = {})
6
- get("/api/v1/calendar_events", params)
7
- end
8
-
9
- def calendar_event(event, params = {})
10
- get("/api/v1/calendar_events/#{event}", params)
11
- end
12
-
13
- def create_calendar_event(params = {})
14
- post("/api/v1/calendar_events", params)
15
- end
16
-
17
- def update_calendar_event(event, params = {})
18
- put("/api/v1/calendar_events/#{event}", params)
19
- end
6
+ prefix "/api/v1/calendar_events/" do
7
+ get :calendar_events
8
+ post :create_calendar_event
20
9
 
21
- def delete_calendar_event(event, params = {})
22
- delete("/api/v1/calendar_events/#{event}", params)
10
+ prefix ":event/" do
11
+ get :calendar_event
12
+ put :update_calendar_event
13
+ delete :delete_calendar_event
14
+ end
23
15
  end
24
16
  end
25
17
  end
@@ -1,13 +1,11 @@
1
1
  module Bearcat
2
2
  class Client < Footrest::Client
3
3
  module CanvasFiles
4
-
5
4
  def upload_file(api_path, file_path, params = {})
6
5
  declare_response = declare_file(api_path, file_params(file_path).merge(params))
7
6
  confirmation_url = post_file(declare_response['upload_url'], declare_response['upload_params'], file_path)
8
7
  confirm_file_upload(confirmation_url)
9
8
  end
10
-
11
9
  end
12
10
  end
13
11
  end