bearcat 0.1

Sign up to get free protection for your applications and to get access to all the features.
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