bearcat 1.3.28 → 1.3.30

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f647eb5f21166dc1aa4383ff33184be11d127b60
4
- data.tar.gz: ce49a99cbdb58e448c2738696a8aea07a2cc441d
3
+ metadata.gz: 5c8d7f5a1481dd58f3e09d2f0be117afb259ab7a
4
+ data.tar.gz: f1ee6a16c5616fe354a5f0ec7654166531d64663
5
5
  SHA512:
6
- metadata.gz: 78df1f29163a3d1aa42a1dfdb2801ba5c623000d3e2c3ed644ec2c41fca00ebe3fcc4048c62217a584600fc6952ba5d70adfc51512a3bba836e80a5aa485d535
7
- data.tar.gz: a128860bd32263d21ddceee32fced977f3b86016609022dc3b3757d8a2a3ef6592398ded9d6c4215ded32d2fb3be394c76100a531738d3ec7bc9b92fe02351c4
6
+ metadata.gz: 1c5567c4f30375c5ab1db0a9f1f36d48e81beffcf28caccfb267344ee2ccd0376fe4643dc0341cf7b9d46f1e8ef005b92c88961b614139321194e102d68d5eef
7
+ data.tar.gz: 02abd72f687e7ac98b4b3fd1c6e8544fdbd16a0aec704cfa0816e185c3902bc5b8e733153bbc95971d4f64d800c178926ff88e5631cae52df578c4a80045de02
data/bearcat.gemspec CHANGED
@@ -24,5 +24,8 @@ Gem::Specification.new do |gem|
24
24
  gem.add_development_dependency "webmock"
25
25
  gem.add_development_dependency 'pry'
26
26
 
27
+ gem.add_dependency "activesupport"
27
28
  gem.add_dependency "footrest", ">= 0.2.2"
29
+ gem.add_dependency "logging", ">= 2.2.2"
30
+ gem.add_dependency "paul_walker", "~> 0.1.1"
28
31
  end
data/lib/bearcat.rb CHANGED
@@ -1,2 +1,54 @@
1
1
  require 'bearcat/version'
2
2
  require 'bearcat/client'
3
+
4
+ module Bearcat
5
+ class << self
6
+ require 'logging'
7
+ attr_writer :enforce_rate_limits, :rate_limit_min, :rate_limits, :max_sleep_seconds,
8
+ :min_sleep_seconds, :logger, :master_rate_limit, :master_mutex,
9
+ :rate_limit_threshold
10
+
11
+ def configure
12
+ yield self if block_given?
13
+ end
14
+
15
+ def rate_limit_min
16
+ @rate_limit_min ||= 175
17
+ end
18
+
19
+ def enforce_rate_limits
20
+ @enforce_rate_limits ||= false
21
+ end
22
+
23
+ def rate_limits
24
+ @rate_limits ||= {}
25
+ end
26
+
27
+ def max_sleep_seconds
28
+ @max_sleep_seconds ||= 60
29
+ end
30
+
31
+ def master_rate_limit
32
+ @master_rate_limit ||= false
33
+ end
34
+
35
+ def master_mutex
36
+ @master_mutex ||= Mutex.new
37
+ end
38
+
39
+ def rate_limit_threshold
40
+ @rate_limit_threshold ||= 125
41
+ end
42
+
43
+ def logger
44
+ return @logger if defined? @logger
45
+ @logger = Logging.logger(STDOUT)
46
+ @logger.level = :debug
47
+ @logger
48
+ end
49
+
50
+ def min_sleep_seconds
51
+ @min_sleep_seconds ||= 5
52
+ end
53
+ end
54
+ end
@@ -19,12 +19,12 @@ module Bearcat
19
19
  @array_key = array_key
20
20
  @page_count = 100
21
21
  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'])
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'])
28
28
  end
29
29
  end
30
30
 
@@ -1,4 +1,7 @@
1
+ require 'active_support/core_ext/hash'
1
2
  require 'footrest/client'
3
+ require 'paul_walker'
4
+
2
5
  module Bearcat
3
6
  class Client < Footrest::Client
4
7
  require 'bearcat/api_array'
@@ -70,11 +73,64 @@ module Bearcat
70
73
  include CustomGradebookColumns
71
74
  include ExternalTools
72
75
 
73
-
74
76
  # Override Footrest request for ApiArray support
75
77
  def request(method, &block)
76
- ApiArray::process_response(connection.send(method, &block), self)
78
+ enforce_rate_limits
79
+ response = connection.send(method, &block)
80
+ apply_rate_limits(response.headers['x-rate-limit-remaining'])
81
+ ApiArray.process_response(response, self)
82
+ end
83
+
84
+ def enforce_rate_limits
85
+ return unless limit_remaining.present?
86
+ return unless limit_remaining < Bearcat.rate_limit_min
87
+
88
+ tts = ((Bearcat.rate_limit_min - limit_remaining) / 5).ceil
89
+ tts = Bearcat.min_sleep_seconds if tts < Bearcat.min_sleep_seconds
90
+ tts = Bearcat.max_sleep_seconds if tts > Bearcat.max_sleep_seconds
91
+
92
+
93
+ message = "Canvas API rate limit minimum #{Bearcat.rate_limit_min} reached. "\
94
+ "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
95
+ "Limit Remaining: #{limit_remaining}"
96
+ Bearcat.logger.debug(message)
97
+
98
+ sleep(tts)
77
99
  end
78
- end
79
100
 
101
+ def apply_rate_limits(limit)
102
+ return if limit.nil?
103
+ self.limit_remaining = limit.to_i
104
+ end
105
+
106
+ def using_master_rate_limit?
107
+ config[:master_rate_limit].present? || Bearcat.master_rate_limit.present?
108
+ end
109
+
110
+ def limit_remaining
111
+ if using_master_rate_limit?
112
+ Bearcat.master_mutex.synchronize do
113
+ limit = PaulWalker::RateLimit.get(config[:token], config[:token])
114
+ if limit.nil?
115
+ PaulWalker::RateLimit.add(config[:token], config[:token], 0, Bearcat::rate_limit_min)
116
+ limit = { current: 0 }.with_indifferent_access
117
+ end
118
+ Bearcat.logger.debug limit['current'].to_s
119
+ limit['current']
120
+ end
121
+ else
122
+ Bearcat.rate_limits[config[:token]]
123
+ end
124
+ end
125
+
126
+ def limit_remaining=(value)
127
+ if using_master_rate_limit?
128
+ Bearcat.master_mutex.synchronize do
129
+ PaulWalker::RateLimit.add(config[:token], config[:token], value, Bearcat::rate_limit_min)
130
+ end
131
+ else
132
+ Bearcat.rate_limits[config[:token]] = value
133
+ end
134
+ end
135
+ end
80
136
  end
@@ -5,6 +5,10 @@ module Bearcat
5
5
  def list_course_folders(course, params = {})
6
6
  get("/api/v1/courses/#{course}/folders", params)
7
7
  end
8
+
9
+ def create_course_folder(course, params = {})
10
+ post("/api/v1/courses/#{course}/folders", params)
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -1,3 +1,3 @@
1
1
  module Bearcat
2
- VERSION = '1.3.28' unless defined?(Bearcat::VERSION)
2
+ VERSION = '1.3.30' unless defined?(Bearcat::VERSION)
3
3
  end
@@ -9,4 +9,10 @@ describe Bearcat::Client::Folders do
9
9
  expect(folders.map { |f| f['id'] }).to eql [1, 593]
10
10
  expect(folders.map { |f| f['full_name'] }).to eql ['course files', 'course files/folder1']
11
11
  end
12
+
13
+ it 'creates a new folder in a course' do
14
+ resp = stub_post(client, '/api/v1/courses/7/folders').to_return(json_response('course_folder.json'))
15
+ folder = client.create_course_folder(7, {name: 'new folder'})
16
+ expect(folder['name']).to eql('new folder')
17
+ end
12
18
  end
@@ -0,0 +1,21 @@
1
+ {
2
+ "context_id": 1,
3
+ "context_type": "Course",
4
+ "created_at": "2015-04-28T19:14:58Z",
5
+ "full_name": "new folder",
6
+ "id": 3,
7
+ "lock_at": null,
8
+ "name": "new folder",
9
+ "parent_folder_id": null,
10
+ "position": null,
11
+ "unlock_at": null,
12
+ "updated_at": "2015-04-28T19:14:58Z",
13
+ "locked": false,
14
+ "folders_url": "http://localhost:3000/api/v1/folders/1/folders",
15
+ "files_url": "http://localhost:3000/api/v1/folders/1/files",
16
+ "files_count": 2,
17
+ "folders_count": 1,
18
+ "hidden": null,
19
+ "locked_for_user": false,
20
+ "hidden_for_user": false
21
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bearcat
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.28
4
+ version: 1.3.30
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Mills, Jake Sorce
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-29 00:00:00.000000000 Z
11
+ date: 2019-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: footrest
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,34 @@ dependencies:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: 0.2.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: logging
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 2.2.2
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.2.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: paul_walker
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.1.1
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.1.1
97
139
  description: Ruby interface for interacting with the canvas API
98
140
  email:
99
141
  - nathanm@instructure.com, jake@instructure.com
@@ -219,6 +261,7 @@ files:
219
261
  - spec/fixtures/course_copy.json
220
262
  - spec/fixtures/course_enrollments.json
221
263
  - spec/fixtures/course_files.json
264
+ - spec/fixtures/course_folder.json
222
265
  - spec/fixtures/course_folders.json
223
266
  - spec/fixtures/course_grading_standards.json
224
267
  - spec/fixtures/course_groups.json
@@ -380,6 +423,7 @@ test_files:
380
423
  - spec/fixtures/course_files.json
381
424
  - spec/fixtures/assignment_section_override.json
382
425
  - spec/fixtures/delete_course.json
426
+ - spec/fixtures/course_folder.json
383
427
  - spec/fixtures/ok.json
384
428
  - spec/fixtures/account_sub_accounts.json
385
429
  - spec/fixtures/course_sections.json