canvas_interactor 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9b740eae5b741f2cc3cb016872d0c1de2c187da0340f00427de63b99d3821077
4
+ data.tar.gz: 8bdb6648bb107a0a6abe6ffce96b61f63e1aa28bc3218347921a24f15294776b
5
+ SHA512:
6
+ metadata.gz: c903d982ff10c452e26953dbf43ce9d9bae5dc93719c3461f4f36a54481c2cd198b4f3baa19256c88e9f7041ab87f03169d3aba768236939aba6f00c75c20ed2
7
+ data.tar.gz: 5fef267c4effc9b4d66493893bfc2767fe5363c964f8663c65f373272ca318f6fe48036063dfebf8e8ce70810d140191514501eb4e1f47331128cf40b1228e8c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Ahmad Hassan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # CanvasInteractor
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'canvas_interactor'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install canvas_interactor
23
+ ```
24
+
25
+ 1.To copy these migrations into the application and migrate run the following command
26
+
27
+ ```
28
+ $ bundle install
29
+ $ bundle exec rake railties:install:migrations
30
+ $ bundle exec rake db:migrate
31
+ ```
32
+
33
+ * If you would like to run migrations only from one engine, you can do it by specifying SCOPE:
34
+
35
+ `$ bin/rails db:migrate SCOPE=canvas_interactor`
36
+
37
+ 2.Then, mount the engine to your app by adding this line to your routes.rb file
38
+
39
+ `mount CanvasInteractor::Engine => "/canvas_interactor"`
40
+
41
+ 3.Next, include the engine in your ApplicationController
42
+
43
+ ```
44
+ class ApplicationController < ActionController::Base
45
+ include CanvasOauth::CanvasApplication
46
+
47
+ ...
48
+ end
49
+ ```
50
+
51
+ After that, create an `canvas.yml` file in your `config/` folder that looks something like this (or see `config/canvas.yml.example` for a template):
52
+
53
+ ```
54
+ default: &default
55
+ key: your_key
56
+ secret: your_secret
57
+
58
+ development:
59
+ <<: *default
60
+
61
+ test:
62
+ <<: *default
63
+
64
+ production:
65
+ <<: *default
66
+ ```
67
+ ## Usage
68
+
69
+ TODO:
70
+
71
+ ## Configuring the Tool Consumer
72
+
73
+ You will need a developer key and secret from canvas, which should be entered into you `canvas.yml` file.
74
+
75
+ ## Quick Start
76
+
77
+ TODO:
78
+
79
+ ## Contributing
80
+ Contributors are welcome.
81
+
82
+ `er.ahmad.hassan@gmail.com`
83
+ https://twitter.com/TheAhmadHassanK
84
+
85
+ ## License
86
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'CanvasInteractor'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ load 'rails/tasks/statistics.rake'
18
+
19
+ require 'bundler/gem_tasks'
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/canvas_interactor .js
2
+ //= link_directory ../stylesheets/canvas_interactor .css
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,6 @@
1
+ module CanvasInteractor
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ include CanvasInteractor::CanvasApplication
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ module CanvasInteractor
2
+ class CanvasController < CanvasInteractor::ApplicationController
3
+ skip_before_action :request_canvas_authentication
4
+
5
+ def oauth
6
+ if verify_oauth2_state(params[:state]) && params[:code]
7
+ if token = canvas.get_access_token(params[:code])
8
+ if CanvasInteractor::Authorization.cache_token(token, user_id, tool_consumer_instance_guid)
9
+ redirect_to main_app.root_path
10
+ else
11
+ render text: "Error: unable to save token"
12
+ end
13
+ else
14
+ render text: "Error: invalid code - #{params[:code]}"
15
+ end
16
+ else
17
+ render text: "#{CanvasInteractor::Config.tool_name} needs access to your account in order to function properly. Please try again and click log in to approve the integration."
18
+ end
19
+ end
20
+
21
+ def verify_oauth2_state(callback_state)
22
+ callback_state.present? && callback_state == session.delete(:oauth2_state)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ module CanvasInteractor
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module CanvasInteractor
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module CanvasInteractor
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module CanvasInteractor
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ module CanvasInteractor
2
+ class Authorization < ApplicationRecord
3
+ validates :canvas_user_id, :token, :last_used_at, presence: true
4
+
5
+ def self.cache_token(token, user_id, tool_consumer_instance_guid)
6
+ create do |t|
7
+ t.token = token
8
+ t.canvas_user_id = user_id
9
+ t.tool_consumer_instance_guid = tool_consumer_instance_guid
10
+ t.last_used_at = Time.now
11
+ end
12
+ end
13
+
14
+ def self.fetch_token(user_id, tool_consumer_instance_guid)
15
+ user_tokens = where(canvas_user_id: user_id, tool_consumer_instance_guid: tool_consumer_instance_guid).order('created_at DESC')
16
+ if canvas_auth = user_tokens.first
17
+ canvas_auth.update_attribute(:last_used_at, Time.now)
18
+ return canvas_auth.token
19
+ end
20
+ end
21
+
22
+ def self.clear_tokens(user_id, tool_consumer_instance_guid)
23
+ where(canvas_user_id: user_id, tool_consumer_instance_guid: tool_consumer_instance_guid).destroy_all
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Canvas interactor</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "canvas_interactor/application", media: "all" %>
9
+ <%= javascript_include_tag "canvas_interactor/application" %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ CanvasInteractor::Engine.routes.draw do
2
+ match '/', to: 'canvas#oauth', via: :get, as: :canvas_oauth
3
+ end
@@ -0,0 +1,12 @@
1
+ class CreateCanvasInteractorAuthorizations < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :canvas_interactor_authorizations do |t|
4
+ t.integer :canvas_user_id
5
+ t.string :tool_consumer_instance_guid, :null => false
6
+ t.string :token
7
+ t.datetime :last_used_at
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ require 'canvas_interactor/engine'
2
+ require 'ostruct'
3
+ require 'httparty'
4
+ require 'link_header'
5
+ require 'canvas_interactor/config'
6
+ require 'canvas_interactor/canvas_application'
7
+ require 'canvas_interactor/canvas_api'
8
+ require 'canvas_interactor/canvas_api_extensions'
9
+ require 'canvas_interactor/canvas_config'
10
+
11
+ module CanvasInteractor
12
+ mattr_accessor :app_root
13
+
14
+ def self.setup
15
+ yield self
16
+ end
17
+
18
+ def self.config
19
+ yield(CanvasInteractor::Config)
20
+ end
21
+ end
@@ -0,0 +1,249 @@
1
+ module CanvasInteractor
2
+ class CanvasApi
3
+ include HTTParty
4
+ PER_PAGE = 50
5
+
6
+ attr_accessor :token, :key, :secret
7
+ attr_reader :canvas_url
8
+
9
+ def initialize(canvas_url, token, key, secret)
10
+ self.canvas_url = canvas_url
11
+ self.token = token
12
+ self.key = key
13
+ self.secret = secret
14
+ end
15
+
16
+ def authenticated_request(method, *params)
17
+ params << {} if params.size == 1
18
+
19
+ params.last[:headers] ||= {}
20
+ params.last[:headers]['Authorization'] = "Bearer #{token}"
21
+
22
+ start = Time.now
23
+
24
+ response = self.class.send(method, *params)
25
+
26
+ Rails.logger.info {
27
+ stop = Time.now
28
+ elapsed = ((stop - start) * 1000).round(2)
29
+
30
+ params.last[:headers].reject! { |k| k == 'Authorization' }
31
+ "API call (#{elapsed}ms): #{method} #{params.inspect}"
32
+ }
33
+
34
+ if response && response.unauthorized?
35
+ if response.headers['WWW-Authenticate'].present?
36
+ raise CanvasApi::Authenticate
37
+ else
38
+ raise CanvasApi::Unauthorized
39
+ end
40
+ else
41
+ return response
42
+ end
43
+ end
44
+
45
+ def paginated_get(*params)
46
+ params[1] ||= {}
47
+ params[1][:query] ||= {}
48
+ params[1][:query][:per_page] = PER_PAGE
49
+
50
+ all_pages = []
51
+
52
+ while params[0] do
53
+ if current_page = authenticated_get(*params)
54
+ all_pages += current_page if valid_page?(current_page)
55
+
56
+ links = LinkHeader.parse(current_page.headers['link'])
57
+ params[0] = links.find_link(["rel", "next"]).try(:href)
58
+ else
59
+ params[0] = nil
60
+ end
61
+ end
62
+
63
+ all_pages
64
+ end
65
+
66
+ def get_report(account_id, report_type, params)
67
+ report = authenticated_post("/api/v1/accounts/#{account_id}/reports/#{report_type}", { body: params })
68
+ report = authenticated_get "/api/v1/accounts/#{account_id}/reports/#{report_type}/#{report['id']}"
69
+ while report['status'] == 'running'
70
+ sleep(4)
71
+ report = authenticated_get "/api/v1/accounts/#{account_id}/reports/#{report_type}/#{report['id']}"
72
+ end
73
+
74
+ if report['status'] == 'complete'
75
+ file_id = report['file_url'].match(/files\/([0-9]+)\/download/)[1]
76
+ file = get_file(file_id)
77
+ return hash_csv(self.class.get(file['url'], limit: 15).parsed_response)
78
+ else
79
+ return report
80
+ end
81
+ end
82
+
83
+ def valid_page?(page)
84
+ page && page.size > 0
85
+ end
86
+
87
+ def get_file(file_id)
88
+ authenticated_get "/api/v1/files/#{file_id}"
89
+ end
90
+
91
+ def get_accounts_provisioning_report(account_id)
92
+ get_report(account_id, :provisioning_csv, 'parameters[accounts]' => true)
93
+ end
94
+
95
+ #Needs to be refactored to somewhere more generic
96
+ def hash_csv(csv_string)
97
+ require 'csv'
98
+
99
+ csv = CSV.parse(csv_string)
100
+ headers = csv.shift
101
+ output = []
102
+
103
+ csv.each do |row|
104
+ hash = {}
105
+ headers.each do |header|
106
+ hash[header] = row.shift.to_s
107
+ end
108
+ output << hash
109
+ end
110
+
111
+ return output
112
+ end
113
+
114
+ def authenticated_get(*params)
115
+ authenticated_request(:get, *params)
116
+ end
117
+
118
+ def authenticated_post(*params)
119
+ authenticated_request(:post, *params)
120
+ end
121
+
122
+ def authenticated_put(*params)
123
+ authenticated_request(:put, *params)
124
+ end
125
+
126
+ def get_courses
127
+ paginated_get "/api/v1/courses"
128
+ end
129
+
130
+ def get_account(account_id)
131
+ authenticated_get "/api/v1/accounts/#{account_id}"
132
+ end
133
+
134
+ def get_account_sub_accounts(account_id)
135
+ paginated_get "/api/v1/accounts/#{account_id}/sub_accounts", { query: { :recursive => true } }
136
+ end
137
+
138
+ def get_account_courses(account_id)
139
+ paginated_get "/api/v1/accounts/#{account_id}/courses"
140
+ end
141
+
142
+ def get_account_users(account_id)
143
+ paginated_get "/api/v1/accounts/#{account_id}/users"
144
+ end
145
+
146
+ def get_course(course_id)
147
+ authenticated_get "/api/v1/courses/#{course_id}"
148
+ end
149
+
150
+ def get_section_enrollments(section_id)
151
+ paginated_get "/api/v1/sections/#{section_id}/enrollments"
152
+ end
153
+
154
+ def get_user_enrollments(user_id)
155
+ paginated_get "/api/v1/users/#{user_id}/enrollments"
156
+ end
157
+
158
+ def get_course_users(course_id)
159
+ paginated_get "/api/v1/courses/#{course_id}/users"
160
+ end
161
+
162
+ def get_all_course_users(course_id)
163
+ paginated_get "/api/v1/courses/#{course_id}/users", { query: {enrollment_state: ["active","invited","rejected","completed","inactive"] } }
164
+ end
165
+
166
+ def get_course_teachers_and_tas(course_id)
167
+ paginated_get "/api/v1/courses/#{course_id}/users", { query: { enrollment_type: ['teacher', 'ta'] } }
168
+ end
169
+
170
+ def get_course_students(course_id)
171
+ paginated_get "/api/v1/courses/#{course_id}/students"
172
+ end
173
+
174
+ def get_section(section_id)
175
+ authenticated_get "/api/v1/sections/#{section_id}"
176
+ end
177
+
178
+ def get_sections(course_id)
179
+ paginated_get "/api/v1/courses/#{course_id}/sections", { query: { :include => ['students', 'avatar_url', 'enrollments'] } }
180
+ end
181
+
182
+ def get_assignments(course_id)
183
+ paginated_get "/api/v1/courses/#{course_id}/assignments"
184
+ end
185
+
186
+ def get_assignment(course_id, assignment_id)
187
+ authenticated_get "/api/v1/courses/#{course_id}/assignments/#{assignment_id}"
188
+ end
189
+
190
+ def get_user_profile(user_id)
191
+ authenticated_get "/api/v1/users/#{user_id}/profile"
192
+ end
193
+
194
+ def create_assignment(course_id, params)
195
+ authenticated_post "/api/v1/courses/#{course_id}/assignments", { body: { assignment: params } }
196
+ end
197
+
198
+ def grade_assignment(course_id, assignment_id, user_id, params)
199
+ authenticated_put "/api/v1/courses/#{course_id}/assignments/#{assignment_id}/submissions/#{user_id}", { body: params }
200
+ end
201
+
202
+ def course_account_id(course_id)
203
+ course = get_course(course_id)
204
+ course['account_id'] if course
205
+ end
206
+
207
+ def root_account_id(account_id)
208
+ if account_id && account = get_account(account_id)
209
+ root_id = account['root_account_id']
210
+ end
211
+
212
+ root_id || account_id
213
+ end
214
+
215
+ def course_root_account_id(course_id)
216
+ root_account_id(course_account_id(course_id))
217
+ end
218
+
219
+ def auth_url(redirect_uri, oauth2_state)
220
+ "#{canvas_url}/login/oauth2/auth?client_id=#{key}&response_type=code&state=#{oauth2_state}&redirect_uri=#{redirect_uri}"
221
+ end
222
+
223
+ def get_access_token(code)
224
+ params = {
225
+ body: {
226
+ client_id: key,
227
+ client_secret: secret,
228
+ code: code
229
+ }
230
+ }
231
+
232
+ response = self.class.post '/login/oauth2/token', params
233
+ self.token = response['access_token']
234
+ end
235
+
236
+ def hex_sis_id(name, value)
237
+ hex = value.unpack("H*")[0]
238
+ return "hex:#{name}:#{hex}"
239
+ end
240
+
241
+ def canvas_url=(value)
242
+ @canvas_url = value
243
+ self.class.base_uri(value)
244
+ end
245
+ end
246
+
247
+ class CanvasApi::Unauthorized < StandardError ; end
248
+ class CanvasApi::Authenticate < StandardError ; end
249
+ end
@@ -0,0 +1,8 @@
1
+ module CanvasInteractor
2
+ class CanvasApiExtensions
3
+ def self.build(canvas_url, user_id, tool_consumer_instance_guid)
4
+ token = CanvasInteractor::Authorization.fetch_token(user_id, tool_consumer_instance_guid)
5
+ CanvasApi.new(canvas_url, token, CanvasConfig.key, CanvasConfig.secret)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,65 @@
1
+ module CanvasInteractor
2
+ module CanvasApplication
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ end
7
+
8
+ included do
9
+ helper_method :canvas
10
+
11
+ rescue_from CanvasApi::Authenticate, with: :reauthenticate
12
+ rescue_from CanvasApi::Unauthorized, with: :unauthorized_canvas_access
13
+ before_action :request_canvas_authentication
14
+ end
15
+
16
+ protected
17
+ def initialize_canvas
18
+ @canvas = ::CanvasInteractor::CanvasApiExtensions.build(canvas_url, user_id, tool_consumer_instance_guid)
19
+ end
20
+
21
+ def canvas
22
+ @canvas || initialize_canvas
23
+ end
24
+
25
+ def canvas_token
26
+ ::CanvasInteractor::Authorization.fetch_token(user_id, tool_consumer_instance_guid)
27
+ end
28
+
29
+ def request_canvas_authentication
30
+ if !params[:code].present? && !canvas_token.present?
31
+ session[:oauth2_state] = SecureRandom.urlsafe_base64(24)
32
+ redirect_to canvas.auth_url(canvas_interactor_url, session[:oauth2_state])
33
+ end
34
+ end
35
+
36
+ def not_acceptable
37
+ render text: "Unable to process request", status: 406
38
+ end
39
+
40
+ def unauthorized_canvas_access
41
+ render text: "Your Canvas Developer Key is not authorized to access this data.", status: 401
42
+ end
43
+
44
+ def reauthenticate
45
+ ::CanvasInteractor::Authorization.clear_tokens(user_id, tool_consumer_instance_guid)
46
+ request_canvas_authentication
47
+ end
48
+
49
+ # these next three methods rely on external session data and either need to
50
+ # be overridden or the session data needs to be set up by the time the
51
+ # oauth filter runs (like with the lti_provider_engine)
52
+
53
+ def canvas_url
54
+ session[:canvas_url]
55
+ end
56
+
57
+ def user_id
58
+ session[:user_id]
59
+ end
60
+
61
+ def tool_consumer_instance_guid
62
+ session[:tool_consumer_instance_guid]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,28 @@
1
+ module CanvasInteractor
2
+ module CanvasConfig
3
+ mattr_accessor :key, :secret
4
+
5
+ def self.load_config
6
+ YAML::load(File.open(config_file))[Rails.env]
7
+ end
8
+
9
+ def self.config_file
10
+ CanvasOauth.app_root.join('config/canvas.yml')
11
+ end
12
+
13
+ def self.setup!
14
+ if File.exists?(config_file)
15
+ Rails.logger.info "Initializing Canvas using configuration in #{config_file}"
16
+ config = load_config
17
+ self.key = config['key']
18
+ self.secret = config['secret']
19
+ elsif ENV['CANVAS_KEY'].present? && ENV['CANVAS_SECRET'].present?
20
+ Rails.logger.info "Initializing Canvas using environment vars CANVAS_KEY and CANVAS_SECRET"
21
+ self.key = ENV['CANVAS_KEY']
22
+ self.secret = ENV['CANVAS_SECRET']
23
+ else
24
+ raise "Warning: Canvas key and secret not configured (RAILS_ENV = #{ENV['RAILS_ENV']})."
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module CanvasInteractor
2
+ Config = OpenStruct.new
3
+ end
@@ -0,0 +1,5 @@
1
+ module CanvasInteractor
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace CanvasInteractor
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module CanvasInteractor
2
+ VERSION = '1.0.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :canvas_interactor do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,259 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: canvas_interactor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ahmad Hassan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-06-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: httparty
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.9.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: link_header
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.6
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.6
61
+ - !ruby/object:Gem::Dependency
62
+ name: pg
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec-its
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec-rails
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: rspec-rails-mocha
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: shoulda-matchers
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: webmock
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: guard-rspec
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ - !ruby/object:Gem::Dependency
188
+ name: rb-fsevent
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ description: Canvas Interactor is a mountable engine for handling the oauth workflow
202
+ with canvas and making api calls from your rails app.
203
+ email:
204
+ - er.ahmad.hassan@gmail.com
205
+ executables: []
206
+ extensions: []
207
+ extra_rdoc_files: []
208
+ files:
209
+ - MIT-LICENSE
210
+ - README.md
211
+ - Rakefile
212
+ - app/assets/config/canvas_interactor_manifest.js
213
+ - app/assets/javascripts/canvas_interactor/application.js
214
+ - app/assets/stylesheets/canvas_interactor/application.css
215
+ - app/controllers/canvas_interactor/application_controller.rb
216
+ - app/controllers/canvas_interactor/canvas_controller.rb
217
+ - app/helpers/canvas_interactor/application_helper.rb
218
+ - app/jobs/canvas_interactor/application_job.rb
219
+ - app/mailers/canvas_interactor/application_mailer.rb
220
+ - app/models/canvas_interactor/application_record.rb
221
+ - app/models/canvas_interactor/authorization.rb
222
+ - app/views/layouts/canvas_interactor/application.html.erb
223
+ - config/routes.rb
224
+ - db/migrate/20180607153145_create_canvas_interactor_authorizations.rb
225
+ - lib/canvas_interactor.rb
226
+ - lib/canvas_interactor/canvas_api.rb
227
+ - lib/canvas_interactor/canvas_api_extensions.rb
228
+ - lib/canvas_interactor/canvas_application.rb
229
+ - lib/canvas_interactor/canvas_config.rb
230
+ - lib/canvas_interactor/config.rb
231
+ - lib/canvas_interactor/engine.rb
232
+ - lib/canvas_interactor/version.rb
233
+ - lib/tasks/canvas_interactor_tasks.rake
234
+ homepage: https://github.com/ahmadhasankhan/canvas_interactor
235
+ licenses:
236
+ - MIT
237
+ metadata: {}
238
+ post_install_message:
239
+ rdoc_options: []
240
+ require_paths:
241
+ - lib
242
+ required_ruby_version: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '0'
247
+ required_rubygems_version: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: '0'
252
+ requirements: []
253
+ rubyforge_project:
254
+ rubygems_version: 2.7.6
255
+ signing_key:
256
+ specification_version: 4
257
+ summary: Canvas Interactor is a mountable engine for handling the oauth workflow with
258
+ canvas and making api calls from your rails app.
259
+ test_files: []