bearcat 0.1
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.
- data/Rakefile +8 -0
- data/bearcat.gemspec +27 -0
- data/lib/bearcat.rb +2 -0
- data/lib/bearcat/api_array.rb +118 -0
- data/lib/bearcat/client.rb +20 -0
- data/lib/bearcat/client/assignments.rb +18 -0
- data/lib/bearcat/client/courses.rb +19 -0
- data/lib/bearcat/client/enrollments.rb +19 -0
- data/lib/bearcat/client/outcome_groups.rb +81 -0
- data/lib/bearcat/client/outcomes.rb +15 -0
- data/lib/bearcat/client/sections.rb +27 -0
- data/lib/bearcat/version.rb +3 -0
- data/spec/bearcat/client/assignments_spec.rb +39 -0
- data/spec/bearcat/client/courses_spec.rb +31 -0
- data/spec/bearcat/client/enrollments_spec.rb +42 -0
- data/spec/bearcat/client/outcome_groups_spec.rb +104 -0
- data/spec/bearcat/client/outcomes_spec.rb +27 -0
- data/spec/bearcat/client/sections_spec.rb +51 -0
- data/spec/bearcat/client_spec.rb +16 -0
- data/spec/bearcat_spec.rb +8 -0
- data/spec/fixtures/assignment_section_override.json +9 -0
- data/spec/fixtures/assignments.json +86 -0
- data/spec/fixtures/conclude_enrollment.json +20 -0
- data/spec/fixtures/course.json +46 -0
- data/spec/fixtures/course_sections.json +20 -0
- data/spec/fixtures/course_students.json +6 -0
- data/spec/fixtures/create_outcome_in_group.json +23 -0
- data/spec/fixtures/create_section.json +1 -0
- data/spec/fixtures/created_assignment.json +25 -0
- data/spec/fixtures/created_course.json +27 -0
- data/spec/fixtures/delete_section.json +1 -0
- data/spec/fixtures/enroll_student.json +20 -0
- data/spec/fixtures/link_unlink_outcome.json +23 -0
- data/spec/fixtures/outcome_group_import.json +22 -0
- data/spec/fixtures/outcome_groups.json +29 -0
- data/spec/fixtures/outcome_subgroup.json +22 -0
- data/spec/fixtures/outcome_subgroups.json +20 -0
- data/spec/fixtures/outcomes.json +33 -0
- data/spec/fixtures/paged_body.json +92 -0
- data/spec/fixtures/section.json +1 -0
- data/spec/fixtures/update_outcome.json +1 -0
- data/spec/fixtures/update_outcome_group.json +22 -0
- data/spec/fixtures/update_section.json +1 -0
- data/spec/fixtures/user_enrollments.json +23 -0
- data/spec/helper.rb +43 -0
- metadata +220 -0
data/Rakefile
ADDED
data/bearcat.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bearcat/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.authors = ["Nathan Mills"]
|
8
|
+
gem.email = ["nathanm@instructure.com"]
|
9
|
+
gem.description = %q{Ruby interface for interacting with the canvas API}
|
10
|
+
gem.summary = %q{Canvas API}
|
11
|
+
|
12
|
+
gem.files = %w[Rakefile bearcat.gemspec]
|
13
|
+
gem.files += Dir.glob("lib/**/*.rb")
|
14
|
+
gem.files += Dir.glob("spec/**/*")
|
15
|
+
gem.test_files = Dir.glob("spec/**/*")
|
16
|
+
gem.name = "bearcat"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = Bearcat::VERSION
|
19
|
+
|
20
|
+
gem.add_development_dependency "rake"
|
21
|
+
gem.add_development_dependency "bundler", ">= 1.0.0"
|
22
|
+
gem.add_development_dependency "rspec", "~> 2.6"
|
23
|
+
gem.add_development_dependency "webmock"
|
24
|
+
gem.add_development_dependency "debugger"
|
25
|
+
|
26
|
+
gem.add_dependency "footrest", ">= 0.1.2"
|
27
|
+
end
|
data/lib/bearcat.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class ApiArray
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :status, :headers, :members
|
6
|
+
|
7
|
+
def self.process_response(response, api_client)
|
8
|
+
if response.body.is_a? Array
|
9
|
+
ApiArray.new response, api_client
|
10
|
+
else
|
11
|
+
response.body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(response, api_client)
|
16
|
+
@api_client = api_client
|
17
|
+
case response.status
|
18
|
+
when 200..206
|
19
|
+
if response.body.is_a?(Array)
|
20
|
+
@members = response.body
|
21
|
+
@status = response.status
|
22
|
+
@headers = response.headers
|
23
|
+
@method = response.env[:method]
|
24
|
+
init_pages(@headers['Link'])
|
25
|
+
end
|
26
|
+
else
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](i)
|
31
|
+
@members[i]
|
32
|
+
end
|
33
|
+
|
34
|
+
def last
|
35
|
+
@members.last
|
36
|
+
end
|
37
|
+
|
38
|
+
def each(&block)
|
39
|
+
@members.each { |member| block.call(member) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def pages?
|
43
|
+
!@link_hash.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def next_page
|
47
|
+
load_page('next')
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def prev_page
|
52
|
+
load_page('prev')
|
53
|
+
end
|
54
|
+
|
55
|
+
def first_page
|
56
|
+
load_page('first')
|
57
|
+
end
|
58
|
+
|
59
|
+
def last_page
|
60
|
+
load_page('last')
|
61
|
+
end
|
62
|
+
|
63
|
+
def all_pages!(page_count = 50)
|
64
|
+
if pages?
|
65
|
+
@page_count = page_count
|
66
|
+
response = get_page(@link_hash['first'])
|
67
|
+
@headers = response.headers
|
68
|
+
@status = response.status
|
69
|
+
@method = response.env[:method]
|
70
|
+
init_pages(@headers[:link])
|
71
|
+
@members = response.body
|
72
|
+
while @link_hash['next']
|
73
|
+
response = get_page(@link_hash['next'])
|
74
|
+
@headers = response.headers
|
75
|
+
@status = response.status
|
76
|
+
@method = response.env[:method]
|
77
|
+
@members.concat(response.body)
|
78
|
+
init_pages(@headers[:link])
|
79
|
+
end
|
80
|
+
@link_hash = {}
|
81
|
+
self
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def init_pages(link_header)
|
88
|
+
@link_hash = {}
|
89
|
+
if @headers.has_key? 'Link'
|
90
|
+
links = link_header.split(/,\s?/)
|
91
|
+
|
92
|
+
links.each do |link|
|
93
|
+
link_parts = link.split(/;\s?/)
|
94
|
+
url = link_parts.shift.strip.gsub(/^<|>$/, '')
|
95
|
+
rel = link_parts.find { |part| part.gsub('"', '').split('=').first == 'rel' }
|
96
|
+
@link_hash[rel.gsub('"', '').split('=').last] = url
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_page(url, params = {})
|
102
|
+
params['per_page'] = @page_count unless params.has_key? 'per_page' || !@page_count
|
103
|
+
query = URI.parse(url).query
|
104
|
+
p = CGI.parse(query).merge(params)
|
105
|
+
u = url.gsub("?#{query}", '')
|
106
|
+
p.each { |k, v| p[k] = v.first if v.is_a?(Array) }
|
107
|
+
@api_client.request(:get, u, p)
|
108
|
+
end
|
109
|
+
|
110
|
+
def load_page(rel)
|
111
|
+
if @link_hash.has_key? rel
|
112
|
+
response = get_page(@link_hash[rel])
|
113
|
+
ApiArray.process_response(response, @api_client)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'footrest/client'
|
2
|
+
require 'bearcat/client/assignments'
|
3
|
+
require 'bearcat/client/courses'
|
4
|
+
require 'bearcat/client/enrollments'
|
5
|
+
require 'bearcat/client/outcome_groups'
|
6
|
+
require 'bearcat/client/outcomes'
|
7
|
+
require 'bearcat/client/sections'
|
8
|
+
|
9
|
+
module Bearcat
|
10
|
+
class Client < Footrest::Client
|
11
|
+
|
12
|
+
include Assignments
|
13
|
+
include Courses
|
14
|
+
include Enrollments
|
15
|
+
include OutcomeGroups
|
16
|
+
include Outcomes
|
17
|
+
include Sections
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class Client < Footrest::Client
|
3
|
+
module Assignments
|
4
|
+
|
5
|
+
def assignments(course, params={})
|
6
|
+
get("/api/v1/courses/#{course}/assignments", params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_assignment_override(course, assignment, params)
|
10
|
+
post("api/v1/courses/#{course}/assignments/#{assignment}/overrides", params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_assignment(course, params={})
|
14
|
+
post("/api/v1/courses/#{course}/assignments", params)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class Client < Footrest::Client
|
3
|
+
module Courses
|
4
|
+
|
5
|
+
def course(course)
|
6
|
+
get("/api/v1/courses/#{course}")
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_course(account_id, params={})
|
10
|
+
post("/api/v1/accounts/#{account_id}/courses", params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def list_users(course, params={})
|
14
|
+
get("/api/v1/courses/#{course}/users", params)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class Client < Footrest::Client
|
3
|
+
module Enrollments
|
4
|
+
|
5
|
+
def user_enrollments(user, params={})
|
6
|
+
get("/api/v1/users/#{user.to_s}/enrollments", params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def enroll_in_section(section, params={})
|
10
|
+
post("/api/v1/sections/#{section.to_s}/enrollments", params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def conclude_enrollment(course, enrollment, params={})
|
14
|
+
delete("/api/v1/courses/#{course}/enrollments/#{enrollment}", params)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class Client < Footrest::Client
|
3
|
+
module OutcomeGroups
|
4
|
+
|
5
|
+
def show_outcome_group(outcome_group_id, params={})
|
6
|
+
get("#{outcomes_context_slug(params)}#{outcome_group_id}")
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_outcome_group(outcome_group_id, params={})
|
10
|
+
put("#{outcomes_context_slug(params)}#{outcome_group_id}", params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete_outcome_group(outcome_group_id, params={})
|
14
|
+
delete("#{outcomes_context_slug(params)}#{outcome_group_id}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def list_linked_outcomes(outcome_group_id, params={})
|
18
|
+
get("#{outcomes_context_slug(params)}#{outcome_group_id}/outcomes")
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_outcome_in_group(outcome_group_id, params={})
|
22
|
+
post("#{outcomes_context_slug(params)}#{outcome_group_id}/outcomes", params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def link_outcome(outcome_group_id, outcome_id, params={})
|
26
|
+
put("#{outcomes_context_slug(params)}#{outcome_group_id}/outcomes/#{outcome_id}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def unlink_outcome(outcome_group_id, outcome_id, params={})
|
30
|
+
delete("#{outcomes_context_slug(params)}#{outcome_group_id}/outcomes/#{outcome_id}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def list_subgroups(outcome_group_id, params={})
|
34
|
+
get("#{outcomes_context_slug(params)}#{outcome_group_id}/subgroups")
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_subgroup(outcome_group_id, params={})
|
38
|
+
post("#{outcomes_context_slug(params)}#{outcome_group_id}/subgroups", params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def import_outcome_group(outcome_group_id, params={})
|
42
|
+
post("#{outcomes_context_slug(params)}#{outcome_group_id}/import", params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def outcomes_context_slug(params)
|
46
|
+
context_hash = params.select { |k, _| k == "account" || k == "course" }
|
47
|
+
|
48
|
+
if context_hash.keys.count > 1
|
49
|
+
raise ArgumentError, "cannot have account and course in params"
|
50
|
+
elsif context_hash.empty?
|
51
|
+
return "#{config.prefix}#{global_slug}"
|
52
|
+
else
|
53
|
+
context_hash_key = context_hash.keys.first
|
54
|
+
case context_hash_key
|
55
|
+
when 'account'
|
56
|
+
"#{config.prefix}#{account_slug(context_hash[context_hash_key])}"
|
57
|
+
when 'course'
|
58
|
+
"#{config.prefix}#{course_slug(context_hash[context_hash_key])}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def account_slug(account_id)
|
65
|
+
"accounts/#{account_id}/outcome_groups/"
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
private
|
70
|
+
def course_slug(course_id)
|
71
|
+
"courses/#{course_id}/outcome_groups/"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def global_slug
|
76
|
+
"global/outcome_groups/"
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Bearcat
|
2
|
+
class Client < Footrest::Client
|
3
|
+
module Sections
|
4
|
+
|
5
|
+
def course_sections(course, params={})
|
6
|
+
get("/api/v1/courses/#{course.to_s}/sections", params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def section(section)
|
10
|
+
get("/api/v1/sections/#{section.to_s}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_section(course, params)
|
14
|
+
post("/api/v1/courses/#{course.to_s}/sections", params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_section(section, params)
|
18
|
+
put("/api/v1/sections/#{section.to_s}", params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete_section(section)
|
22
|
+
delete("/api/v1/sections/#{section.to_s}")
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Bearcat::Client::Assignments do
|
4
|
+
before do
|
5
|
+
@client = Bearcat::Client.new(prefix: "http://canvas.instructure.com", token: "test_token")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns all assignments for a course" do
|
9
|
+
stub_get(@client, "/api/v1/courses/3/assignments").to_return(json_response("assignments.json"))
|
10
|
+
assignments = @client.assignments(3)
|
11
|
+
expect(assignments.count).to eq(2)
|
12
|
+
expect(assignments.first["assignment_group_id"]).to eq(53)
|
13
|
+
expect(assignments.first["id"]).to eq(123)
|
14
|
+
expect(assignments.first["due_at"]).to eq(nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates an assignment override for a section" do
|
18
|
+
stub_post(@client, "/api/v1/courses/310/assignments/123/overrides")
|
19
|
+
.with(:body => {"assignment_override"=>{"course_section_id"=>"74", "due_at"=>"2013-06-27T21:08:46Z"}})
|
20
|
+
.to_return(json_response("assignment_section_override.json"))
|
21
|
+
override = @client.create_assignment_override(310, 123, {
|
22
|
+
"assignment_override[course_section_id]" => 74,
|
23
|
+
"assignment_override[due_at]" => "2013-06-27T21:08:46Z"
|
24
|
+
})
|
25
|
+
expect(override["all_day"]).to eq(false)
|
26
|
+
expect(override["due_at"]).to eq("2013-06-27T15:08:46-06:00")
|
27
|
+
expect(override["id"]).to eq(1)
|
28
|
+
expect(override["course_section_id"]).to eq(74)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "creates a new assignment" do
|
32
|
+
name = "new assignment"
|
33
|
+
stub_post(@client, "/api/v1/courses/1/assignments").with(body: {"assignment" => {"name" => name}}).to_return(json_response("created_assignment.json"))
|
34
|
+
assignment = @client.create_assignment(1, {"assignment" => {"name" => name}})
|
35
|
+
expect(assignment["name"]).to eq(name)
|
36
|
+
expect(assignment["id"]).to eq(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Bearcat::Client::Sections do
|
4
|
+
before do
|
5
|
+
@client = Bearcat::Client.new(prefix: "http://canvas.instructure.com", token: "test_token")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns a section" do
|
9
|
+
stub_get(@client, "/api/v1/courses/3").to_return(json_response("course.json"))
|
10
|
+
course = @client.course(3)
|
11
|
+
expect(course['name']).to eq('Course 3')
|
12
|
+
expect(course['id']).to eq(3)
|
13
|
+
expect(course['start_at']).to eq('2012-06-01T00:00:00-06:00')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "creates a new course" do
|
17
|
+
name = "new course"
|
18
|
+
stub_post(@client, "/api/v1/accounts/1/courses").with(body: {"course" => {"name" => name}}).to_return(json_response("created_course.json"))
|
19
|
+
course = @client.create_course(1, {"course[name]" => name})
|
20
|
+
expect(course['name']).to eq(name)
|
21
|
+
expect(course['id']).to eq(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "lists all of the students in a course" do
|
25
|
+
stub_get(@client, "/api/v1/courses/1/users?enrollment_type=student").to_return(json_response("course_students.json"))
|
26
|
+
students = @client.list_users(1, {"enrollment_type" => "student"})
|
27
|
+
expect(students['name']).to eq('test@student.com')
|
28
|
+
expect(students['id']).to eq(2)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|