lti_skydrive 1.1.0 → 1.2.0
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 +8 -8
- data/Rakefile +20 -1
- data/app/assets/javascripts/skydrive/bundle.js +1792 -1794
- data/app/controllers/skydrive/application_controller.rb +1 -1
- data/app/controllers/skydrive/files_controller.rb +0 -5
- data/app/controllers/skydrive/launch_controller.rb +69 -19
- data/app/controllers/skydrive/session_controller.rb +1 -1
- data/app/models/skydrive/token.rb +1 -3
- data/app/models/skydrive/user.rb +18 -0
- data/app/views/layouts/skydrive/application.html.erb +0 -1
- data/app/views/skydrive/launch/app_redirect.html.erb +1 -1
- data/app/views/skydrive/launch/launch_error.html.erb +4 -0
- data/config/initializers/sharepoint.rb +2 -1
- data/config/routes.rb +1 -0
- data/lib/skydrive/client.rb +62 -29
- data/lib/skydrive/file.rb +1 -1
- data/lib/skydrive/raven_logger.rb +16 -0
- data/lib/skydrive/version.rb +1 -1
- data/spec/controllers/launch_controller_spec.rb +209 -0
- data/spec/lib/skydrive/client_spec.rb +185 -0
- data/spec/lib/skydrive/file_spec.rb +63 -0
- data/spec/lib/skydrive/folder_spec.rb +19 -0
- data/spec/models/api_key_spec.rb +21 -0
- data/spec/spec_helper.rb +49 -0
- data/{test/dummy → spec/test_app}/README.rdoc +0 -0
- data/{test/dummy → spec/test_app}/Rakefile +1 -1
- data/{test/dummy → spec/test_app}/app/assets/javascripts/application.js +0 -0
- data/{test/dummy → spec/test_app}/app/assets/stylesheets/application.css +0 -0
- data/{test/dummy → spec/test_app}/app/controllers/application_controller.rb +0 -0
- data/{test/dummy → spec/test_app}/app/helpers/application_helper.rb +0 -0
- data/{test/dummy → spec/test_app}/app/views/layouts/application.html.erb +1 -1
- data/{test/dummy → spec/test_app}/bin/bundle +0 -0
- data/{test/dummy → spec/test_app}/bin/rails +0 -0
- data/{test/dummy → spec/test_app}/bin/rake +0 -0
- data/{test/dummy → spec/test_app}/config/application.rb +7 -15
- data/{test/dummy → spec/test_app}/config/boot.rb +1 -1
- data/{test/dummy → spec/test_app}/config/database.yml +8 -8
- data/{test/dummy → spec/test_app}/config/environment.rb +1 -1
- data/{test/dummy → spec/test_app}/config/environments/development.rb +1 -1
- data/{test/dummy → spec/test_app}/config/environments/production.rb +2 -2
- data/{test/dummy → spec/test_app}/config/environments/test.rb +1 -1
- data/{test/dummy → spec/test_app}/config/initializers/backtrace_silencers.rb +0 -0
- data/{test/dummy → spec/test_app}/config/initializers/filter_parameter_logging.rb +0 -0
- data/{test/dummy → spec/test_app}/config/initializers/inflections.rb +0 -0
- data/{test/dummy → spec/test_app}/config/initializers/mime_types.rb +0 -0
- data/{test/dummy → spec/test_app}/config/initializers/secret_token.rb +1 -1
- data/spec/test_app/config/initializers/session_store.rb +3 -0
- data/{test/dummy → spec/test_app}/config/initializers/wrap_parameters.rb +0 -0
- data/{test/dummy → spec/test_app}/config/routes.rb +0 -0
- data/spec/test_app/config/sharepoint.yml +17 -0
- data/{test/dummy → spec/test_app}/config.ru +0 -0
- data/{test/dummy → spec/test_app}/db/schema.rb +0 -1
- data/{test/dummy → spec/test_app}/public/404.html +0 -0
- data/{test/dummy → spec/test_app}/public/422.html +0 -0
- data/{test/dummy → spec/test_app}/public/500.html +0 -0
- data/spec/test_app/public/assets/application-710416f2f225dfabdc1644964d73bb6e.js +14 -0
- data/spec/test_app/public/assets/application-f83fdeca1df44ae142d477b21c557b7b.css +14 -0
- data/spec/test_app/public/assets/bootstrap/glyphicons-halflings-regular-0658df48a6185a0d17acc3f86ff2073b.svg +229 -0
- data/spec/test_app/public/assets/bootstrap/glyphicons-halflings-regular-0c86ed38ad91a73661c05f22fed185b3.woff +0 -0
- data/spec/test_app/public/assets/bootstrap/glyphicons-halflings-regular-b4268224f45a1b3e5575b458b0f68636.ttf +0 -0
- data/spec/test_app/public/assets/bootstrap/glyphicons-halflings-regular-bb146793ac4efa4609bb0512921fc8f2.eot +0 -0
- data/spec/test_app/public/assets/lti_box_engine/application-e4115e9d7a64091d8e938ebe100de7b8.js +20 -0
- data/spec/test_app/public/assets/lti_box_engine/banner-cc541d8b706841c4c101e20c54f57cd7.png +0 -0
- data/spec/test_app/public/assets/lti_box_engine/icon-f4a2da1d67a72ae4962d0152d0b25d0d.png +0 -0
- data/{test/dummy → spec/test_app}/public/favicon.ico +0 -0
- metadata +98 -170
- data/test/controllers/skydrive/ember_controller_test.rb +0 -11
- data/test/dummy/config/initializers/session_store.rb +0 -3
- data/test/dummy/config/locales/en.yml +0 -23
- data/test/dummy/config/sharepoint.yml +0 -31
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/log/development.log +0 -47831
- data/test/dummy/tmp/cache/assets/development/sprockets/007f0b35cdfe0e199e160ca7d8c6549f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/10c0e5e7b23b9f05226f908616b8f740 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/17ae7f285d886e07f4db626a659963f8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/18e08230de276dd3238e77cf0826189c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/1a88e6194e0de973583e2adefdc5ac18 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/1fc004bfb36f4c31a590a840e552a5c9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2e4c5fbbf5bf02ef9bd200cce7a7ebc1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/358b2efd0a896115b444b609bc46fca1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/3d9987487f81715791eeeed72ad127da +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/430f864d22195be98702ac04bc5343b8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/432817256836b657a99d2c2b8afb82bf +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/45f9e6cdd4d120d901099ccb2018fb4f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5186e21495c07e70e882425df200732c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/53de95b978e9c09ae4d2300888e937e5 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5dc21d3b55fc9ca8fbf6582c7fac6c44 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5dd770bdd24bc838e0604eaf2e1d62e0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5ed30435bc197334c5c942a45ad637d8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/62ef3761af670019ed9f926b6893f7b7 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/74283c36e06317a57bf88c444c66eabe +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/7edc3f1ebc1331bb170f75ee2ce227b1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/88b8a5c8da15ecfa6e7154a661b242a6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/8b73f393f902dcdfe3dd05afb0f5e2d1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9531ae5356e65c245a5f006c8dd1c577 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/98060297d706705e3fc0f7857857dbb9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/98871292949834ebaa9e1eebdd3dca4f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9e208aeff46e060cb20a25456d6be611 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9ebc8e4abeebfae73c59c391e49d0172 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/a082682acbe6ed53f5b69ec4d6b336a4 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/a7cec1f4ecd136cb80122e121cb63b01 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/aa4851494096d3890157afaad27cc407 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ab90d34dfc192bf5fc19836906a3dc23 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/afcc3340d4944bf68dd319f3b59c3237 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b0728e2ff6ca4e7f91dbeff31978a9c9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b54c3c599c3ca4b4f26aa9df12514a56 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b7a1dd5c7d3c2aca0f451fcbc5737cb8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b83d0d640ae485682db0dff00a1ef7d8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/bcaf1a8e8073121541dcae50e896db44 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/be723463abbc85ed29cf5a5840fbfed0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/c16ddf1297328a121de46d0ce47df069 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ccc62e82e5e329c6af0ccf81402ac838 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d47464809e089dba588360f9f0a59d50 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d9044923a28026f1c6540cebecebb7e0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/deacdc0b128cd87d3275fed230cbb7d5 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/fbbc449abae90cbd209354c203662388 +0 -0
- data/test/helpers/skydrive/ember_helper_test.rb +0 -6
- data/test/integration/navigation_test.rb +0 -10
- data/test/skydrive_test.rb +0 -7
- data/test/test_helper.rb +0 -15
|
@@ -10,10 +10,6 @@ module Skydrive
|
|
|
10
10
|
head :unauthorized
|
|
11
11
|
return
|
|
12
12
|
end
|
|
13
|
-
|
|
14
|
-
if current_user.token && current_user.token.not_before > Time.now
|
|
15
|
-
current_user.token.refresh!(skydrive_client)
|
|
16
|
-
end
|
|
17
13
|
end
|
|
18
14
|
|
|
19
15
|
def index
|
|
@@ -56,4 +52,3 @@ module Skydrive
|
|
|
56
52
|
end
|
|
57
53
|
end
|
|
58
54
|
end
|
|
59
|
-
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
require 'raven'
|
|
1
2
|
require 'ims/lti'
|
|
2
3
|
|
|
3
4
|
module Skydrive
|
|
5
|
+
|
|
6
|
+
ERROR_NO_API_KEY = "Unable to get an access token, your state is invalid"
|
|
7
|
+
ERROR_JSON_PARSE = "JSON::ParserError"
|
|
8
|
+
ERROR_SKY_DRIVE_API = "Skydrive::APIErrorException"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
4
12
|
class LaunchController < ApplicationController
|
|
5
13
|
include ActionController::Cookies
|
|
6
14
|
before_filter :ensure_authenticated_user, only: :skydrive_authorized
|
|
@@ -46,16 +54,26 @@ module Skydrive
|
|
|
46
54
|
return
|
|
47
55
|
end
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
user_id = tp.get_custom_param('masquerading_user_id') || tp.user_id
|
|
58
|
+
is_masquerading = user_id == tp.get_custom_param('masquerading_user_id')
|
|
59
|
+
name = is_masquerading ? 'masqueraded session' : tp.lis_person_name_full
|
|
60
|
+
email = is_masquerading ? 'masqueraded session' : tp.lis_person_contact_email_primary
|
|
61
|
+
|
|
62
|
+
user = @account.users.where(username: user_id).first ||
|
|
50
63
|
@account.users.create(
|
|
51
|
-
lti_user_id:
|
|
52
|
-
name:
|
|
53
|
-
username:
|
|
54
|
-
email:
|
|
64
|
+
lti_user_id: user_id,
|
|
65
|
+
name: name,
|
|
66
|
+
username: user_id,
|
|
67
|
+
email: email
|
|
55
68
|
)
|
|
56
69
|
|
|
57
|
-
user.
|
|
70
|
+
if !is_masquerading && (user.email != email || user.name != name)
|
|
71
|
+
user.email = email
|
|
72
|
+
user.name = name
|
|
73
|
+
user.save!
|
|
74
|
+
end
|
|
58
75
|
|
|
76
|
+
user.ensure_token
|
|
59
77
|
user.cleanup_api_keys
|
|
60
78
|
|
|
61
79
|
code = user.session_api_key(params).oauth_code
|
|
@@ -65,30 +83,40 @@ module Skydrive
|
|
|
65
83
|
def skydrive_authorized
|
|
66
84
|
skydrive_token = current_user.token
|
|
67
85
|
if skydrive_token && skydrive_token.requires_refresh?
|
|
68
|
-
|
|
86
|
+
begin
|
|
87
|
+
skydrive_client.refresh_token = skydrive_token.refresh_token
|
|
88
|
+
skydrive_token.refresh!(skydrive_client)
|
|
89
|
+
rescue Skydrive::APIResponseErrorException => error
|
|
90
|
+
current_user.reset_token!
|
|
91
|
+
end
|
|
69
92
|
end
|
|
70
93
|
|
|
71
94
|
if skydrive_token && skydrive_token.is_valid?
|
|
72
95
|
render json: {}, status: 201
|
|
73
96
|
else
|
|
74
97
|
code = current_user.api_keys.active.skydrive_oauth.create.oauth_code
|
|
75
|
-
|
|
76
98
|
render text: skydrive_client.oauth_authorize_redirect_uri(microsoft_oauth_url, state: code), status: 401
|
|
77
99
|
end
|
|
78
100
|
end
|
|
79
101
|
|
|
80
102
|
def microsoft_oauth
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
103
|
+
begin
|
|
104
|
+
api_key = ApiKey.trade_oauth_code_for_access_token(params['state'])
|
|
105
|
+
raise RuntimeError, ERROR_NO_API_KEY unless api_key
|
|
106
|
+
|
|
107
|
+
@current_user = api_key.user
|
|
108
|
+
skydrive_client.request_oauth_token(params['code'], microsoft_oauth_url)
|
|
109
|
+
service = skydrive_client.get_my_files_service()
|
|
110
|
+
current_user.token.resource = service["serviceResourceId"]
|
|
111
|
+
current_user.token.refresh!(skydrive_client)
|
|
112
|
+
|
|
113
|
+
personal_url = skydrive_client.get_personal_url(service["serviceEndpointUri"]).gsub(/\/Documents$/,'/')
|
|
114
|
+
current_user.token.update_attribute(:personal_url, personal_url)
|
|
115
|
+
|
|
116
|
+
redirect_to "#{root_path}oauth/callback"
|
|
117
|
+
rescue Exception => api_error
|
|
118
|
+
launch_exception_handler api_error
|
|
119
|
+
end
|
|
92
120
|
end
|
|
93
121
|
|
|
94
122
|
def xml_config
|
|
@@ -107,6 +135,7 @@ module Skydrive
|
|
|
107
135
|
tc.canvas_homework_submission!
|
|
108
136
|
tc.canvas_account_navigation!
|
|
109
137
|
tc.canvas_course_navigation!(visibility: 'admin')
|
|
138
|
+
tc.set_custom_param('masquerading_user_id', '$Canvas.masqueradingUser.userId')
|
|
110
139
|
render xml: tc.to_xml
|
|
111
140
|
end
|
|
112
141
|
|
|
@@ -114,5 +143,26 @@ module Skydrive
|
|
|
114
143
|
render json: {}, status: 200
|
|
115
144
|
current_user.token.destroy
|
|
116
145
|
end
|
|
146
|
+
|
|
147
|
+
def launch_error
|
|
148
|
+
@title = %s{Ooops! Something went terribly wrong!}
|
|
149
|
+
@message = %s{Not sure what happened, or how you got here?!}
|
|
150
|
+
render status: 400, layout: "skydrive/error"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
def launch_exception_handler(api_error)
|
|
155
|
+
RavenLogger.capture_exception(api_error)
|
|
156
|
+
@api_error = api_error
|
|
157
|
+
@title = %s{Ooops! Something went terribly wrong!}
|
|
158
|
+
@message = "An error or invalid response was received from the OneDrive API. Close any popups, refresh the page, and relaunch OneDrive."
|
|
159
|
+
|
|
160
|
+
if api_error.message == ERROR_NO_API_KEY
|
|
161
|
+
@title = %s{Unable to retrieve an access token}
|
|
162
|
+
@message = %s{It looks like your using an old page. Close any popups, and relaunch OneDrive.}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
render action: :launch_error, status: 400, layout: "skydrive/error"
|
|
166
|
+
end
|
|
117
167
|
end
|
|
118
168
|
end
|
|
@@ -13,13 +13,11 @@ module Skydrive
|
|
|
13
13
|
|
|
14
14
|
def refresh!(client)
|
|
15
15
|
results = {}
|
|
16
|
-
|
|
17
16
|
results = client.refresh_token(resource: resource)
|
|
18
|
-
|
|
19
17
|
if results.key? 'access_token'
|
|
20
18
|
attrs = ['token_type', 'expires_in', 'expires_on', 'not_before', 'resource', 'access_token', 'refresh_token']
|
|
21
19
|
update_attributes(results.reject{|a| !attrs.include?(a)})
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
|
-
end
|
|
23
|
+
end
|
data/app/models/skydrive/user.rb
CHANGED
|
@@ -24,5 +24,23 @@ module Skydrive
|
|
|
24
24
|
def valid_skydrive_token?
|
|
25
25
|
!!self.token && self.token.is_valid?
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
def ensure_token
|
|
29
|
+
self.token = self.create_token unless self.token
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def reset_token!
|
|
33
|
+
self.token.delete
|
|
34
|
+
ensure_token
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Convenience method
|
|
38
|
+
def onedrive_client
|
|
39
|
+
@onedrive_client ||=
|
|
40
|
+
Client.new(SHAREPOINT.merge(
|
|
41
|
+
personal_url: self.token.personal_url,
|
|
42
|
+
token: self.token.access_token
|
|
43
|
+
))
|
|
44
|
+
end
|
|
27
45
|
end
|
|
28
46
|
end
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<p>result : <%= @result %></p>
|
|
1
|
+
<p>result : <%= @result %></p>
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
require 'yaml'
|
|
2
|
+
SHAREPOINT = YAML.load(File.read("#{Rails.root}/config/sharepoint.yml"))[Rails.env].symbolize_keys
|
data/config/routes.rb
CHANGED
|
@@ -24,6 +24,7 @@ Skydrive::Engine.routes.draw do
|
|
|
24
24
|
get 'config' => 'launch#xml_config'
|
|
25
25
|
|
|
26
26
|
post 'oauth2/token' => 'api_keys#oauth2_token'
|
|
27
|
+
match 'error' => 'launch#launch_error', :via => [:get, :post]
|
|
27
28
|
|
|
28
29
|
# forward all other requests to react application
|
|
29
30
|
get '*path', to: 'ember#index'
|
data/lib/skydrive/client.rb
CHANGED
|
@@ -3,16 +3,32 @@ require 'curb'
|
|
|
3
3
|
require 'json'
|
|
4
4
|
require 'mimemagic'
|
|
5
5
|
require 'jwt'
|
|
6
|
+
require 'skydrive/raven_logger'
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
module Skydrive
|
|
10
|
+
class APIErrorException < RuntimeError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class APIResponseErrorException < RuntimeError
|
|
14
|
+
attr_reader :response, :code, :description
|
|
15
|
+
def initialize(response)
|
|
16
|
+
@response = response
|
|
17
|
+
@code = response['error']
|
|
18
|
+
@description = response['error_description']
|
|
19
|
+
super("#{@code}: #{@description}\n#{response}")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
9
23
|
class Client
|
|
10
24
|
include ActionView::Helpers::NumberHelper
|
|
11
25
|
|
|
12
26
|
attr_accessor :client_id, :client_secret, :guid, :personal_url, :token, :refresh_token
|
|
13
27
|
|
|
14
28
|
def initialize(options = {})
|
|
15
|
-
options.each
|
|
29
|
+
options.each do |key, val|
|
|
30
|
+
self.send("#{key}=", val) if self.respond_to?("#{key}=")
|
|
31
|
+
end
|
|
16
32
|
end
|
|
17
33
|
|
|
18
34
|
# URL used to authorize this app for a sharepoint tenant
|
|
@@ -42,7 +58,7 @@ module Skydrive
|
|
|
42
58
|
|
|
43
59
|
RestClient.post endpoint, options do |response, request, result|
|
|
44
60
|
log_restclient_response(response, request, result)
|
|
45
|
-
results = format_results(
|
|
61
|
+
results = format_results(parse_api_response(response))
|
|
46
62
|
self.token = results['access_token']
|
|
47
63
|
self.refresh_token = results['refresh_token']
|
|
48
64
|
results
|
|
@@ -69,7 +85,7 @@ module Skydrive
|
|
|
69
85
|
|
|
70
86
|
RestClient.post endpoint, options do |response, request, result|
|
|
71
87
|
log_restclient_response(response, request, result)
|
|
72
|
-
results = format_results(
|
|
88
|
+
results = format_results(parse_api_response(response))
|
|
73
89
|
self.token = results['access_token']
|
|
74
90
|
self.refresh_token = results['refresh_token']
|
|
75
91
|
results
|
|
@@ -123,7 +139,7 @@ module Skydrive
|
|
|
123
139
|
new_file.content_tag = f['ContentTag']
|
|
124
140
|
folder.files << new_file
|
|
125
141
|
end
|
|
126
|
-
|
|
142
|
+
|
|
127
143
|
sub_folders = api_call(CGI::unescape(data['Folders']['__deferred']['uri']))['results']
|
|
128
144
|
sub_folders.each do |sf|
|
|
129
145
|
|
|
@@ -152,37 +168,49 @@ module Skydrive
|
|
|
152
168
|
end
|
|
153
169
|
|
|
154
170
|
def api_call(url, headers = {})
|
|
155
|
-
|
|
156
|
-
uri = URI.escape(url)
|
|
171
|
+
begin
|
|
157
172
|
|
|
158
|
-
|
|
173
|
+
url.gsub!("https:/i", "https://i")
|
|
174
|
+
uri = URI.escape(url)
|
|
159
175
|
|
|
160
|
-
headers['Authorization'] = "Bearer #{token}" unless headers.has_key? 'Authorization'
|
|
161
|
-
headers['Accept'] = "application/json; odata=verbose" unless headers.has_key? 'Accept'
|
|
162
176
|
|
|
163
|
-
|
|
164
|
-
headers
|
|
165
|
-
end
|
|
177
|
+
headers['Authorization'] = "Bearer #{token}" unless headers.has_key? 'Authorization'
|
|
178
|
+
headers['Accept'] = "application/json; odata=verbose" unless headers.has_key? 'Accept'
|
|
166
179
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
buffer << data
|
|
171
|
-
data.size
|
|
172
|
-
}
|
|
173
|
-
c.on_header { |data|
|
|
174
|
-
headers << data
|
|
175
|
-
data.size
|
|
176
|
-
}
|
|
177
|
-
c.perform
|
|
180
|
+
c = Curl::Easy.new(uri) do |http|
|
|
181
|
+
headers.each {|k,v| http.headers[k] = v if v }
|
|
182
|
+
end
|
|
178
183
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
headers = []
|
|
185
|
+
buffer = ""
|
|
186
|
+
c.on_body { |data|
|
|
187
|
+
buffer << data
|
|
188
|
+
data.size
|
|
189
|
+
}
|
|
190
|
+
c.on_header { |data|
|
|
191
|
+
headers << data
|
|
192
|
+
data.size
|
|
193
|
+
}
|
|
194
|
+
c.perform
|
|
195
|
+
|
|
196
|
+
result = parse_api_response(buffer)
|
|
197
|
+
rescue Exception => error
|
|
198
|
+
pid = generate_pid
|
|
199
|
+
headerOutput = c.headers.map {|k,v| "#{k}: #{v}"}.join("\n[#{pid}] - ")
|
|
200
|
+
backtrace_output = error.backtrace.join("\n[#{pid}] - ")
|
|
201
|
+
buffer_output = buffer.split("\n").join("\n[#{pid}] - ")
|
|
202
|
+
|
|
203
|
+
Skydrive.logger.error("[#{pid}] SKYDRIVE ERROR: #{error.class.to_s} ◊ #{error}")
|
|
204
|
+
Skydrive.logger.info("[#{pid}] SKYDRIVE BACKTRACE: \n[#{pid}] - #{backtrace_output}")
|
|
205
|
+
Skydrive.logger.info("[#{pid}] SKYDRIVE REQUEST: #{uri.to_s}")
|
|
206
|
+
Skydrive.logger.info("[#{pid}] SKYDRIVE REQUEST HEADERS:\n[#{pid}] - #{headerOutput}")
|
|
207
|
+
Skydrive.logger.info("[#{pid}] SKYDRIVE RESPONSE HEADERS:\n[#{pid}] - #{headers.join(' - ')}")
|
|
208
|
+
Skydrive.logger.info("[#{pid}] SKYDRIVE RESPONSE BODY:\n[#{pid}] - #{buffer_output}");
|
|
209
|
+
Skydrive.logger.info("[#{pid}] END --\n");
|
|
210
|
+
RavenLogger.capture_exception(error)
|
|
211
|
+
raise error
|
|
212
|
+
end
|
|
184
213
|
|
|
185
|
-
result = JSON.parse(buffer)
|
|
186
214
|
result["d"] || result
|
|
187
215
|
end
|
|
188
216
|
|
|
@@ -206,5 +234,10 @@ module Skydrive
|
|
|
206
234
|
(0...8).map { (65 + rand(26)).chr }.join
|
|
207
235
|
end
|
|
208
236
|
|
|
237
|
+
def parse_api_response(body)
|
|
238
|
+
result = JSON.parse(body)
|
|
239
|
+
raise APIResponseErrorException, result if result["error"]
|
|
240
|
+
result
|
|
241
|
+
end
|
|
209
242
|
end
|
|
210
243
|
end
|
data/lib/skydrive/file.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Skydrive
|
|
|
33
33
|
self.kind = mm.comment
|
|
34
34
|
self.suffix = mm.extensions.last
|
|
35
35
|
|
|
36
|
-
if allowed_extensions.
|
|
36
|
+
if allowed_extensions.blank? || (allowed_extensions & mm.extensions).size > 0
|
|
37
37
|
self.is_embeddable = true
|
|
38
38
|
else
|
|
39
39
|
self.is_embeddable = false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'raven'
|
|
2
|
+
|
|
3
|
+
module Skydrive
|
|
4
|
+
class RavenLogger
|
|
5
|
+
ENV_KEY = "RAVEN_SKYDRIVE_DSN"
|
|
6
|
+
|
|
7
|
+
def self.capture_exception(error)
|
|
8
|
+
return if Rails.env.test?
|
|
9
|
+
if (ENV[ENV_KEY])
|
|
10
|
+
config = Raven.configuration
|
|
11
|
+
config.dsn = ENV.fetch(ENV_KEY)
|
|
12
|
+
end
|
|
13
|
+
Raven.capture_exception(error, {configuration: config})
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/skydrive/version.rb
CHANGED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Skydrive
|
|
4
|
+
describe LaunchController, :type => :controller do
|
|
5
|
+
|
|
6
|
+
account = Account.find_or_create_by!(key: "one", secret: "not_two" )
|
|
7
|
+
let(:email) {'user@email.com'}
|
|
8
|
+
let(:username) {'user'}
|
|
9
|
+
let(:name) {'User'}
|
|
10
|
+
let(:sharepoint_client_domain) {'login.windows.net'}
|
|
11
|
+
|
|
12
|
+
let(:account) {account}
|
|
13
|
+
let(:user) {account.users.find_or_initialize_by(email: 'user@email.com', username: 'user', name: 'User')}
|
|
14
|
+
|
|
15
|
+
describe '#basic_launch' do
|
|
16
|
+
|
|
17
|
+
before(:each) do
|
|
18
|
+
tp = IMS::LTI::ToolProvider.new(nil, nil, {})
|
|
19
|
+
tp.lis_person_contact_email_primary = email
|
|
20
|
+
tp.set_custom_param('sharepoint_client_domain', 'test')
|
|
21
|
+
tp.user_id = username
|
|
22
|
+
tp.lis_person_name_full = name
|
|
23
|
+
|
|
24
|
+
allow_any_instance_of(LaunchController).to receive(:tool_provider).and_return(tp)
|
|
25
|
+
controller.instance_variable_set("@account", account)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "creates a new user" do
|
|
29
|
+
expect(User.where(email: email).count).to be(0)
|
|
30
|
+
|
|
31
|
+
post 'basic_launch', use_route: :skydrive
|
|
32
|
+
expect(response).to be_redirect, response.body
|
|
33
|
+
|
|
34
|
+
user = User.where(email: email).first!
|
|
35
|
+
expect(user.email).to eq(email)
|
|
36
|
+
expect(user.username).to eq(username)
|
|
37
|
+
expect(user.name).to eq(name)
|
|
38
|
+
|
|
39
|
+
expect(user.token).to be_a Token
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "updates existing users' name and email" do
|
|
43
|
+
user.save
|
|
44
|
+
tp = IMS::LTI::ToolProvider.new(nil, nil, {})
|
|
45
|
+
tp.lis_person_contact_email_primary = "updated_email@example.com"
|
|
46
|
+
tp.set_custom_param('sharepoint_client_domain', 'test')
|
|
47
|
+
tp.user_id = username
|
|
48
|
+
tp.lis_person_name_full = "Updated Name"
|
|
49
|
+
allow_any_instance_of(LaunchController).to receive(:tool_provider).and_return(tp)
|
|
50
|
+
|
|
51
|
+
post 'basic_launch', use_route: :skydrive
|
|
52
|
+
expect(response).to be_redirect, response.body
|
|
53
|
+
|
|
54
|
+
user = User.where(username: username).first!
|
|
55
|
+
expect(user.email).to eq("updated_email@example.com")
|
|
56
|
+
expect(user.username).to eq(username)
|
|
57
|
+
expect(user.name).to eq("Updated Name")
|
|
58
|
+
expect(user.token).to be_a Token
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "returns a valid oauth code" do
|
|
62
|
+
post 'basic_launch', use_route: :skydrive
|
|
63
|
+
|
|
64
|
+
code = response.header['Location'].split('/').last
|
|
65
|
+
api_key = ApiKey.where(oauth_code: code).first!
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "find existing users" do
|
|
69
|
+
user.save
|
|
70
|
+
|
|
71
|
+
post 'basic_launch', use_route: :skydrive
|
|
72
|
+
code = response.header['Location'].split('/').last
|
|
73
|
+
api_key = ApiKey.where(oauth_code: code).first!
|
|
74
|
+
expect(api_key.user).to eq(user)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "cleans out expired tokens" do
|
|
78
|
+
user.save
|
|
79
|
+
api_key = user.session_api_key
|
|
80
|
+
api_key.update_attributes(expired_at: Time.now)
|
|
81
|
+
|
|
82
|
+
post 'basic_launch', use_route: :skydrive
|
|
83
|
+
|
|
84
|
+
expect(ApiKey.where(id: api_key.id).count).to be(0)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
let(:masquerading_user_id) {'this_is_a_masqueraded_id'}
|
|
90
|
+
let(:masquerading_email) {'masquerading_user@asd.com'}
|
|
91
|
+
let(:masquerading_name) { 'Dr. masquerading name'}
|
|
92
|
+
let(:masquerading_user) {account.users.find_or_initialize_by(email: masquerading_email, username: masquerading_user_id, name: masquerading_name)}
|
|
93
|
+
|
|
94
|
+
describe '#basic_launch masqueraded' do
|
|
95
|
+
|
|
96
|
+
before(:each) do
|
|
97
|
+
tp = IMS::LTI::ToolProvider.new(nil, nil, {})
|
|
98
|
+
tp.lis_person_contact_email_primary = email
|
|
99
|
+
tp.set_custom_param('sharepoint_client_domain', 'test')
|
|
100
|
+
tp.set_custom_param('masquerading_user_id', masquerading_user_id)
|
|
101
|
+
tp.user_id = username
|
|
102
|
+
tp.lis_person_name_full = name
|
|
103
|
+
|
|
104
|
+
allow_any_instance_of(LaunchController).to receive(:tool_provider).and_return(tp)
|
|
105
|
+
controller.instance_variable_set("@account", account)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "creates a new user with masqueraded user" do
|
|
109
|
+
expect(User.where(username: masquerading_user_id).count).to be(0)
|
|
110
|
+
|
|
111
|
+
post 'basic_launch', use_route: :skydrive
|
|
112
|
+
expect(response).to be_redirect, response.body
|
|
113
|
+
|
|
114
|
+
user = User.where(username: masquerading_user_id).first!
|
|
115
|
+
expect(user.email).to_not eq(email)
|
|
116
|
+
expect(user.username).to eq(masquerading_user_id)
|
|
117
|
+
expect(user.name).to_not eq(name)
|
|
118
|
+
|
|
119
|
+
expect(user.token).to be_a Token
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "returns a valid oauth code with masqueraded user" do
|
|
123
|
+
post 'basic_launch', use_route: :skydrive
|
|
124
|
+
|
|
125
|
+
code = response.header['Location'].split('/').last
|
|
126
|
+
api_key = ApiKey.where(oauth_code: code).first!
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "find existing users with masqueraded user" do
|
|
130
|
+
masquerading_user.save
|
|
131
|
+
|
|
132
|
+
post 'basic_launch', use_route: :skydrive
|
|
133
|
+
code = response.header['Location'].split('/').last
|
|
134
|
+
api_key = ApiKey.where(oauth_code: code).first!
|
|
135
|
+
expect(api_key.user).to eq(masquerading_user)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "find existing users with masqueraded user" do
|
|
139
|
+
masquerading_user.save
|
|
140
|
+
|
|
141
|
+
post 'basic_launch', use_route: :skydrive
|
|
142
|
+
code = response.header['Location'].split('/').last
|
|
143
|
+
api_key = ApiKey.where(oauth_code: code).first!
|
|
144
|
+
|
|
145
|
+
user = api_key.user
|
|
146
|
+
expect(user).to eq(masquerading_user)
|
|
147
|
+
expect(user.email).to eq(masquerading_email)
|
|
148
|
+
expect(user.username).to eq(masquerading_user_id)
|
|
149
|
+
expect(user.name).to eq(masquerading_name)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
it "doesn't update existing users' name and email if they are masquerading" do
|
|
154
|
+
|
|
155
|
+
masquerading_user.save
|
|
156
|
+
|
|
157
|
+
tp = IMS::LTI::ToolProvider.new(nil, nil, {})
|
|
158
|
+
tp.lis_person_contact_email_primary = "updated_email@example.com"
|
|
159
|
+
tp.set_custom_param('sharepoint_client_domain', 'test')
|
|
160
|
+
tp.user_id = username
|
|
161
|
+
tp.lis_person_name_full = "Updated Name"
|
|
162
|
+
allow_any_instance_of(LaunchController).to receive(:tool_provider).and_return(tp)
|
|
163
|
+
|
|
164
|
+
post 'basic_launch', use_route: :skydrive
|
|
165
|
+
expect(response).to be_redirect, response.body
|
|
166
|
+
|
|
167
|
+
user = User.where(username: username).first!
|
|
168
|
+
expect(user.email).to eq("updated_email@example.com")
|
|
169
|
+
expect(user.username).to eq(username)
|
|
170
|
+
expect(user.name).to eq("Updated Name")
|
|
171
|
+
expect(user.token).to be_a Token
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "cleans out expired tokens with masqueraded user" do
|
|
175
|
+
masquerading_user.save
|
|
176
|
+
api_key = masquerading_user.session_api_key
|
|
177
|
+
api_key.update_attributes(expired_at: Time.now)
|
|
178
|
+
|
|
179
|
+
post 'basic_launch', use_route: :skydrive
|
|
180
|
+
|
|
181
|
+
expect(ApiKey.where(id: api_key.id).count).to be(0)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe '#skydrive_authorized' do
|
|
186
|
+
|
|
187
|
+
it "returns a skydrive_auth url when the skydrive token is invalid" do
|
|
188
|
+
user.save
|
|
189
|
+
user.token = Token.create()
|
|
190
|
+
|
|
191
|
+
allow_any_instance_of(LaunchController).to receive(:current_user).and_return(user)
|
|
192
|
+
|
|
193
|
+
post 'skydrive_authorized', use_route: :skydrive
|
|
194
|
+
expect(response.code).to eq("401")
|
|
195
|
+
expect(response.body).to include sharepoint_client_domain
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "returns a 200 when the skydrive token is valid" do
|
|
199
|
+
user.save
|
|
200
|
+
user.token = Token.create(access_token: 'token', expires_on: 1.week.from_now)
|
|
201
|
+
|
|
202
|
+
allow_any_instance_of(LaunchController).to receive(:current_user).and_return(user)
|
|
203
|
+
|
|
204
|
+
post 'skydrive_authorized', use_route: :skydrive
|
|
205
|
+
expect(response).to be_success
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|