bearcat 1.5.39 → 1.6.0.beta1

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: 162fc05f04d1d475f69cdd6cab1d449539d288284cb89868487be991922da485
4
- data.tar.gz: 936bfa6f545ce8bd7f0fe81c15f938d1232fcbdd3685869caae7e8c47ca7aba0
3
+ metadata.gz: 88b94b32414c5a59f1fd3be18678f529de9bef97ee3e10116db68062edeebad2
4
+ data.tar.gz: 62e2edd04e91abc3c4b328e81e54e2f9545be448c62497d01e509c54fd6aeb27
5
5
  SHA512:
6
- metadata.gz: 63da23efc98f40c13824887429bd5df839054a6d0c28f14ce213745ad7811b2c453f34a9ee1e31871c42928017f9f1fee2d7a02744dc8880c621ba25a3efb6b1
7
- data.tar.gz: 77094d36014b3ffded25baf37d58647877ae7689691f673bc2606407be493e1120f388437172ff43ebc2ccce0e55f20d32aeaa576b6ef49e239b4e2add0ca225
6
+ metadata.gz: 374c77ba34fcc3583710cdf54984a5806d328ed0cc1d23edfed8c90051ab4a1225c079243c50497edeeaeb4eac11979aa794403550d33312a5906ab33f5d1cc2
7
+ data.tar.gz: cc6690b3e892cafa054c1a4f775d0ee39c3bcf7f8ea0834f023c345c8e6416e22c03aa40f2bb1dbd9605f91ef6d48db3a7a2fd811b70b24913b6bc254d1cd4ed
@@ -71,18 +71,6 @@ module Badgrcat
71
71
  delete :delete_assertion
72
72
  end
73
73
  end
74
-
75
- prefix "v2/backpack" do
76
- prefix "/assertions" do
77
- get :backpack_assertions
78
- end
79
- end
80
-
81
- prefix "v2/users" do
82
- prefix "/self" do
83
- get :get_user_profile
84
- end
85
- end
86
74
  end
87
75
  end
88
76
  end
@@ -198,7 +198,7 @@ module Bearcat
198
198
  path = response.env[:url].path
199
199
  if path.match(/.*\/(courses||groups)\/\d+\/conferences/)
200
200
  key = 'conferences'
201
- elsif path.match(/.*\/accounts\/[^\/]+\/terms/)
201
+ elsif path.match(/.*\/accounts\/(?:(?:\d+~)?\d+|self)\/terms/)
202
202
  key = 'enrollment_terms'
203
203
  end
204
204
  end
@@ -1,67 +1,17 @@
1
1
  module Bearcat
2
- class GraphqlError < StandardError
3
- attr_reader :response
4
-
5
- def initialize(message, response: nil)
6
- super(message)
7
- @response = response
8
- end
9
- end
10
-
11
2
  class Client < Footrest::Client
12
- # Request body format should be:
13
- # - { query: "query string" }
14
- # - "query string"
15
- # - "path/to/gql/file", may be absolute, relative to application root, or relative to `app/graphql`. `.gql` extension is optional.
3
+ # Request body format should be: { query: "query string" }. More info in README.md
16
4
  module GraphQL
17
- def graphql_query(query, args = {})
18
- if query.is_a?(String)
19
- if /\A\w+\Z/.match?(query) && !query.include?("{")
20
- query = query.underscore
21
- @@gql_cache ||= {}
22
-
23
- query = cache_on_class("gql:#{query}") do
24
- paths = []
25
-
26
- pn = Pathname.new(query)
27
- if pn.absolute?
28
- paths << query
29
- else
30
- paths << Rails.root.join("app", "graphql", query)
31
- paths << Rails.root.join(query)
32
- end
33
-
34
- paths = paths.flat_map do |path|
35
- [path, "#{path}.gql"]
36
- end
37
-
38
- query = paths.find do |path|
39
- File.exist?(path)
40
- end
41
-
42
- File.read(query)
43
- end
44
- end
45
-
46
- args.symbolize_keys!
47
-
48
- query = query.gsub(/\{\{(.*?)\}\}/) do |_m|
49
- match = Regexp.last_match
50
- key = match[1].strip.to_sym
51
- args[key]
52
- end
53
5
 
6
+ def graphql_query(query)
7
+ if query.is_a?(String)
54
8
  query = {
55
9
  query: query
56
10
  }
57
11
  end
58
-
59
- result = post('/api/graphql', query)
60
- raise GraphqlError.new("Error running GraphQL query:\n#{result["errors"].to_json}", response: result) if result["errors"].present?
61
-
62
- # TODO: It'd be nice to unwrap and return result["data"] directly, but we want to keep backwards compatibility
63
- result
12
+ post('/api/graphql', query)
64
13
  end
14
+
65
15
  end
66
16
  end
67
17
  end
@@ -5,29 +5,50 @@ module Bearcat
5
5
  module Reports
6
6
  extend ClientModule
7
7
 
8
- prefix "/api/v1/accounts/:account/reports/" do
8
+ PREFIX = "/api/v1/accounts"
9
+
10
+ prefix "#{PREFIX}/:account/reports/" do
9
11
  get :report_list
10
- post :start_report, ":report_name"
11
12
  get :report_history, ":report_name"
12
13
  get :report_status, ":report_name/:report_id"
13
14
  delete :delete_report, ":report_name/:report_id"
14
15
  end
15
16
 
16
- def download_report(url, save_location=nil)
17
- require 'open-uri'
18
- open_uri_stream = URI.open(url, {
19
- 'User-Agent' => "Bearcat/#{Bearcat::VERSION} (#{RUBY_PLATFORM})",
20
- 'Authorization' => "Bearer #{config[:token]}"
21
- })
17
+ def start_report(canvas_account_id, report_name, payload)
18
+ post("#{PREFIX}/#{canvas_account_id}/reports/#{report_name}", payload)
19
+ rescue Bearcat::MiscExceptions::Conflict => e
20
+ JSON.parse(e.response.response_body)
21
+ end
22
22
 
23
+ def download_report(url, save_location=nil)
24
+ #This method takes the verified URL returned in a Canvas report (attachment['url']), and if
25
+ #a save_location is included, it will download it in chunks to the disk to save memory. You
26
+ #can also download the report to memory if you do not include a save location.
27
+ attempts = 0
28
+ begin
29
+ uri = URI.parse(url)
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = true if url.start_with?('https')
32
+ response = http.head(uri.to_s)
33
+ url = response['Location']
34
+ attempts += 1
35
+ end while attempts <= 5 && (response.code == '301' || response.code == '302' || response.code == '307')
36
+ http = Net::HTTP.new(uri.host, uri.port)
37
+ http.use_ssl = true if uri.to_s.start_with?('https')
23
38
  if save_location
24
- save_location = save_location.path if save_location.respond_to?(:path)
25
- IO.copy_stream(open_uri_stream, save_location)
26
- save_location
39
+ File.open(save_location, 'wb') do |file|
40
+ http.request_get(uri.to_s) do |resp|
41
+ resp.read_body do |segment|
42
+ file.write(segment)
43
+ end
44
+ end
45
+ end
27
46
  else
28
- CSV.parse(open_uri_stream.read, headers: true)
47
+ response = http.request_get(uri.to_s)
48
+ CSV.parse(response.read_body, headers: true)
29
49
  end
30
50
  end
51
+
31
52
  end
32
53
  end
33
54
  end
File without changes
@@ -37,19 +37,9 @@ module Bearcat
37
37
  super
38
38
  connection.builder.insert(Footrest::RaiseFootrestErrors, ExtendedRaiseFootrestErrors)
39
39
  connection.builder.delete(Footrest::RaiseFootrestErrors)
40
- end
41
-
42
- def self.cache_on_self(key, &block)
43
- @cache ||= {}
44
- if Rails.env.development? || Rails.env.test?
45
- block.call
46
- else
47
- @cache[key] ||= block.call
48
- end
49
- end
50
40
 
51
- def cache_on_class(key, &block)
52
- self.class.cache_on_self(key, &block)
41
+ connection.builder.insert(Faraday::Request::UrlEncoded, Faraday::Request::JSON)
42
+ connection.builder.delete(Faraday::Request::UrlEncoded)
53
43
  end
54
44
 
55
45
  protected
@@ -0,0 +1,10 @@
1
+ module Bearcat
2
+ module MiscExceptions
3
+ # This exception is not part of the Footrest::HttpError module
4
+ class Conflict < Footrest::HttpError::BadRequest
5
+ def self.===(exception)
6
+ exception.status == 409
7
+ end
8
+ end
9
+ end
10
+ end
@@ -11,8 +11,8 @@ module Bearcat
11
11
  KNOWN_REDIS_URL_ENVS = %w[REDIS_URL REDISTOGO_URL REDISCLOUD_URL].freeze
12
12
 
13
13
  class << self
14
- def configured?(prefix, explicit: true)
15
- determine_redis_provider(prefix: prefix, explicit: explicit).present?
14
+ def configured?(prefix, explicit: false)
15
+ determine_redis_provider(prefix: prefix, explicit: true)
16
16
  end
17
17
 
18
18
  def create(options = {})
@@ -97,13 +97,10 @@ module Bearcat::SpecHelpers
97
97
  end
98
98
  when String
99
99
  raise "Cannot use method :auto when passing string endpoint" if method == :auto
100
- endpoint = Regexp.escape(endpoint)
101
- endpoint = endpoint.gsub("\\*\\*", ".+")
102
- endpoint = endpoint.gsub("\\*", "[^/]+")
103
- { method: method, url: endpoint }
100
+ { method: method, url: Regexp.escape(endpoint) }
104
101
  when Regexp
105
102
  raise "Cannot use method :auto when passing regex endpoint" if method == :auto
106
- { method: method, url: endpoint.to_s }
103
+ { method: method, url: Regexp.escape(endpoint) }
107
104
  end
108
105
  end
109
106
 
@@ -1,3 +1,3 @@
1
1
  module Bearcat
2
- VERSION = '1.5.39' unless defined?(Bearcat::VERSION)
2
+ VERSION = '1.6.0.beta1' unless defined?(Bearcat::VERSION)
3
3
  end
data/lib/bearcat.rb CHANGED
@@ -1,21 +1,18 @@
1
1
  require 'bearcat/version'
2
2
  require 'bearcat/client'
3
- require 'bearcat/redis_connection'
3
+ require 'bearcat/misc_exceptions/conflict'
4
4
 
5
5
  module Bearcat
6
6
  class << self
7
7
  require 'logger'
8
8
  attr_accessor :master_rate_limit
9
- attr_writer :rate_limit_min, :rate_limits, :max_sleep_seconds,
10
- :min_sleep_seconds, :logger, :rate_limiter
9
+ attr_writer :rate_limit_min, :rate_limits, :max_sleep_seconds, :min_sleep_seconds, :logger
11
10
 
12
11
  def configure
13
12
  yield self if block_given?
14
13
  end
15
14
 
16
- def rate_limiter
17
- @rate_limiter
18
- end
15
+ attr_accessor :rate_limiter
19
16
 
20
17
  def rate_limit_min
21
18
  @rate_limit_min ||= 175
@@ -31,6 +28,7 @@ module Bearcat
31
28
 
32
29
  def logger
33
30
  return @logger if defined? @logger
31
+
34
32
  @logger = Logger.new(STDOUT)
35
33
  @logger.level = Logger::DEBUG
36
34
  @logger
@@ -38,14 +36,13 @@ module Bearcat
38
36
 
39
37
  def redis_pool
40
38
  require 'bearcat/redis_connection'
41
- @redis_pool ||= Bearcat::RedisConnection.create(env_prefix: "BEARCAT")
39
+ @redis_pool ||= Bearcat::RedisConnection.create(env_prefix: 'BEARCAT')
42
40
  end
43
41
 
44
- def redis
45
- raise ArgumentError, "requires a block" unless block_given?
46
- redis_pool.with do |conn|
47
- yield conn
48
- end
42
+ def redis(&block)
43
+ raise ArgumentError, 'requires a block' unless block_given?
44
+
45
+ redis_pool.with(&block)
49
46
  end
50
47
  end
51
48
  end
@@ -48,6 +48,7 @@ describe Bearcat::Client::Reports do
48
48
  it 'downloads a report to disk' do
49
49
  report = IO.read(fixture('file.csv'))
50
50
  tempfile = Tempfile.new('report')
51
+ stub_request(:head, 'https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string').to_return(status: 200, body: report)
51
52
  stub_request(:get,'https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string').to_return(status: 200, body: report)
52
53
  @client.download_report('https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string', tempfile)
53
54
  csv = CSV.read(tempfile, headers: true)
@@ -58,10 +59,12 @@ describe Bearcat::Client::Reports do
58
59
  it 'follows redirects' do
59
60
  report = IO.read(fixture('file.csv'))
60
61
  tempfile = Tempfile.new('report')
61
- stub_request(:get, 'https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string')
62
+ stub_request(:head, 'https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string')
62
63
  .to_return(status: 302, body: 'You are being redirected',headers: {'Location' => 'https://cluster1-files.instructure.com/files/1/download?download_frd=1&sf_verifier=verifier=1478139862&user_id=1&verifier=verifier'})
63
- stub_request(:get, 'https://cluster1-files.instructure.com/files/1/download?download_frd=1&sf_verifier=verifier=1478139862&user_id=1&verifier=verifier')
64
+ stub_request(:head, 'https://cluster1-files.instructure.com/files/1/download?download_frd=1&sf_verifier=verifier=1478139862&user_id=1&verifier=verifier')
64
65
  .to_return(status: 302, body: 'You are being redirected', headers: {'Location' => 'https://instructure-uploads.s3.amazonaws.com/account_1/attachments/1/assignment_submission.csv'})
66
+ stub_request(:head, 'https://instructure-uploads.s3.amazonaws.com/account_1/attachments/1/assignment_submission.csv')
67
+ .to_return(status: 200)
65
68
  stub_request(:get, 'https://instructure-uploads.s3.amazonaws.com/account_1/attachments/1/assignment_submission.csv')
66
69
  .to_return(status: 200, body: report)
67
70
  @client.download_report('https://canvas.instructure.com/files/1/download?download_frd=1&verifier=string', tempfile)
data/spec/helper.rb CHANGED
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bearcat
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.39
4
+ version: 1.6.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure CustomDev
@@ -219,6 +219,7 @@ files:
219
219
  - lib/bearcat/client/tabs.rb
220
220
  - lib/bearcat/client/users.rb
221
221
  - lib/bearcat/client_module.rb
222
+ - lib/bearcat/misc_exceptions/conflict.rb
222
223
  - lib/bearcat/rate_limiting.rb
223
224
  - lib/bearcat/rate_limiting/functions.lua
224
225
  - lib/bearcat/rate_limiting/increment_bucket.lua
@@ -444,7 +445,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
444
445
  - !ruby/object:Gem::Version
445
446
  version: '0'
446
447
  requirements: []
447
- rubygems_version: 3.6.7
448
+ rubygems_version: 3.6.9
448
449
  specification_version: 4
449
450
  summary: Canvas API
450
451
  test_files: