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.
Files changed (46) hide show
  1. data/Rakefile +8 -0
  2. data/bearcat.gemspec +27 -0
  3. data/lib/bearcat.rb +2 -0
  4. data/lib/bearcat/api_array.rb +118 -0
  5. data/lib/bearcat/client.rb +20 -0
  6. data/lib/bearcat/client/assignments.rb +18 -0
  7. data/lib/bearcat/client/courses.rb +19 -0
  8. data/lib/bearcat/client/enrollments.rb +19 -0
  9. data/lib/bearcat/client/outcome_groups.rb +81 -0
  10. data/lib/bearcat/client/outcomes.rb +15 -0
  11. data/lib/bearcat/client/sections.rb +27 -0
  12. data/lib/bearcat/version.rb +3 -0
  13. data/spec/bearcat/client/assignments_spec.rb +39 -0
  14. data/spec/bearcat/client/courses_spec.rb +31 -0
  15. data/spec/bearcat/client/enrollments_spec.rb +42 -0
  16. data/spec/bearcat/client/outcome_groups_spec.rb +104 -0
  17. data/spec/bearcat/client/outcomes_spec.rb +27 -0
  18. data/spec/bearcat/client/sections_spec.rb +51 -0
  19. data/spec/bearcat/client_spec.rb +16 -0
  20. data/spec/bearcat_spec.rb +8 -0
  21. data/spec/fixtures/assignment_section_override.json +9 -0
  22. data/spec/fixtures/assignments.json +86 -0
  23. data/spec/fixtures/conclude_enrollment.json +20 -0
  24. data/spec/fixtures/course.json +46 -0
  25. data/spec/fixtures/course_sections.json +20 -0
  26. data/spec/fixtures/course_students.json +6 -0
  27. data/spec/fixtures/create_outcome_in_group.json +23 -0
  28. data/spec/fixtures/create_section.json +1 -0
  29. data/spec/fixtures/created_assignment.json +25 -0
  30. data/spec/fixtures/created_course.json +27 -0
  31. data/spec/fixtures/delete_section.json +1 -0
  32. data/spec/fixtures/enroll_student.json +20 -0
  33. data/spec/fixtures/link_unlink_outcome.json +23 -0
  34. data/spec/fixtures/outcome_group_import.json +22 -0
  35. data/spec/fixtures/outcome_groups.json +29 -0
  36. data/spec/fixtures/outcome_subgroup.json +22 -0
  37. data/spec/fixtures/outcome_subgroups.json +20 -0
  38. data/spec/fixtures/outcomes.json +33 -0
  39. data/spec/fixtures/paged_body.json +92 -0
  40. data/spec/fixtures/section.json +1 -0
  41. data/spec/fixtures/update_outcome.json +1 -0
  42. data/spec/fixtures/update_outcome_group.json +22 -0
  43. data/spec/fixtures/update_section.json +1 -0
  44. data/spec/fixtures/user_enrollments.json +23 -0
  45. data/spec/helper.rb +43 -0
  46. metadata +220 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :test => :spec
8
+ task :default => :spec
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,2 @@
1
+ require 'bearcat/version'
2
+ require 'bearcat/client'
@@ -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,15 @@
1
+ module Bearcat
2
+ class Client < Footrest::Client
3
+ module Outcomes
4
+
5
+ def show_outcome(id)
6
+ get("/api/v1/outcomes/#{id}")
7
+ end
8
+
9
+ def update_outcome(id, params={})
10
+ put("/api/v1/outcomes/#{id}", params)
11
+ end
12
+
13
+ end
14
+ end
15
+ 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,3 @@
1
+ module Bearcat
2
+ VERSION = '0.1' unless defined?(Bearcat::VERSION)
3
+ 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