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 +4 -4
- data/lib/badgrcat/client/methods.rb +0 -12
- data/lib/bearcat/api_array.rb +1 -1
- data/lib/bearcat/client/graph_ql.rb +5 -55
- data/lib/bearcat/client/reports.rb +33 -12
- data/lib/bearcat/client/submissions.rb +0 -0
- data/lib/bearcat/client.rb +2 -12
- data/lib/bearcat/misc_exceptions/conflict.rb +10 -0
- data/lib/bearcat/redis_connection.rb +2 -2
- data/lib/bearcat/spec_helpers.rb +2 -5
- data/lib/bearcat/version.rb +1 -1
- data/lib/bearcat.rb +9 -12
- data/spec/bearcat/client/reports_spec.rb +5 -2
- data/spec/helper.rb +0 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 88b94b32414c5a59f1fd3be18678f529de9bef97ee3e10116db68062edeebad2
|
|
4
|
+
data.tar.gz: 62e2edd04e91abc3c4b328e81e54e2f9545be448c62497d01e509c54fd6aeb27
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/bearcat/api_array.rb
CHANGED
|
@@ -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\/
|
|
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
|
-
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
data/lib/bearcat/client.rb
CHANGED
|
@@ -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
|
-
|
|
52
|
-
|
|
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
|
|
@@ -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:
|
|
15
|
-
determine_redis_provider(prefix: prefix, explicit:
|
|
14
|
+
def configured?(prefix, explicit: false)
|
|
15
|
+
determine_redis_provider(prefix: prefix, explicit: true)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def create(options = {})
|
data/lib/bearcat/spec_helpers.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
|
103
|
+
{ method: method, url: Regexp.escape(endpoint) }
|
|
107
104
|
end
|
|
108
105
|
end
|
|
109
106
|
|
data/lib/bearcat/version.rb
CHANGED
data/lib/bearcat.rb
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
require 'bearcat/version'
|
|
2
2
|
require 'bearcat/client'
|
|
3
|
-
require 'bearcat/
|
|
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
|
-
|
|
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:
|
|
39
|
+
@redis_pool ||= Bearcat::RedisConnection.create(env_prefix: 'BEARCAT')
|
|
42
40
|
end
|
|
43
41
|
|
|
44
|
-
def redis
|
|
45
|
-
raise ArgumentError,
|
|
46
|
-
|
|
47
|
-
|
|
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(:
|
|
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(:
|
|
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.
|
|
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.
|
|
448
|
+
rubygems_version: 3.6.9
|
|
448
449
|
specification_version: 4
|
|
449
450
|
summary: Canvas API
|
|
450
451
|
test_files:
|