d2l_sdk 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ require_relative 'requests'
2
+ require 'json-schema'
3
+
4
+ ##################
5
+ ## ACTIONS: ######
6
+ ##################
7
+
8
+ # TODO: Delete a file or folder from the current user’s locker.
9
+ # => DELETE /d2l/api/le/(version)/locker/myLocker/(path)
10
+ # TODO: Delete a file or folder from the provided user’s locker.
11
+ # => DELETE /d2l/api/le/(version)/locker/user/(userId)/(path)
12
+ # TODO: Retrieve a specific object from the current user’s locker.
13
+ # => GET /d2l/api/le/(version)/locker/myLocker/(path)
14
+ # TODO: Retrieve a specific object from a provided user’s locker.
15
+ # => GET /d2l/api/le/(version)/locker/user/(userId)/(path)
16
+ # TODO: Add a new file or folder to the current user’s locker.
17
+ # => POST /d2l/api/le/(version)/locker/myLocker/(path)
18
+ # TODO: Add a new file or folder to the provided user’s locker.
19
+ # => POST /d2l/api/le/(version)/locker/user/(userId)/(path)
20
+ # TODO: Rename a folder in the current user’s locker.
21
+ # => PUT /d2l/api/le/(version)/locker/myLocker/(path)
22
+ # TODO: Rename a folder in the provided user’s locker.
23
+ # => PUT /d2l/api/le/(version)/locker/user/(userId)/(path)
24
+
25
+ ##################
26
+ ## LOCKERS: ######
27
+ ##################
28
+
29
+ # TODO: Delete a file or folder from the locker of a group in the provided org unit.
30
+ # => DELETE /d2l/api/le/(version)/(orgUnitId)/locker/group/(groupId)/(path)
31
+ # TODO: Determine if a locker has been set up for a group category within an org unit.
32
+ # => GET /d2l/api/lp/(version)/(orgUnitId)/groupcategories/(groupCategoryId)/locker
33
+ # TODO: Retrieve a specific object from a provided group’s locker.
34
+ # => GET /d2l/api/le/(version)/(orgUnitId)/locker/group/(groupId)/(path)
35
+ # TODO: Set up the locker for a group category within an org unit.
36
+ # => POST /d2l/api/lp/(version)/(orgUnitId)/groupcategories/(groupCategoryId)/locker
37
+ # TODO: Add a new file or folder to the locker for a group in the provided org unit.
38
+ # => POST /d2l/api/le/(version)/(orgUnitId)/locker/group/(groupId)/(path)
39
+ # TODO: Rename a folder in the locker for a group in the provided org unit.
40
+ # => PUT /d2l/api/le/(version)/(orgUnitId)/locker/group/(groupId)/(path)
@@ -0,0 +1,34 @@
1
+ require_relative 'requests'
2
+ require 'json-schema'
3
+
4
+ ##################
5
+ ## ACTIONS: ######
6
+ ##################
7
+
8
+ # TODO: Remove an LTI link.
9
+ # => DELETE /d2l/api/le/(version)/lti/link/(ltiLinkId)
10
+ # TODO: Retrieve the information for all LTI links registered for an org unit.
11
+ # => GET /d2l/api/le/(version)/lti/link/(orgUnitId)/
12
+ # TODO: Retrieve the information for a particular LTI link.
13
+ # => GET /d2l/api/le/(version)/lti/link/(orgUnitId)/(ltiLinkId)
14
+ # TODO: Register a new LTI link for an org unit.
15
+ # => POST /d2l/api/le/(version)/lti/link/(orgUnitId)
16
+ # TODO: Build a new quicklink around an existing LTI link.
17
+ # => POST /d2l/api/le/(version)/lti/quicklink/(orgUnitId)/(ltiLinkId)
18
+ # TODO: Update the information associated with a registered LTI link.
19
+ # => PUT /d2l/api/le/(version)/lti/link/(ltiLinkId)
20
+
21
+ #############################
22
+ ## LTI TOOL PROVIDERS: ######
23
+ #############################
24
+
25
+ # TODO: Remove the registration for an LTI tool provider.
26
+ # => DELETE /d2l/api/le/(version)/lti/tp/(tpId)
27
+ # TODO: Retrieve the information for all LTI tool providers registered for an org unit.
28
+ # => GET /d2l/api/le/(version)/lti/tp/(orgUnitId)/
29
+ # TODO: Retrieve the information for a particular LTI tool provider.
30
+ # => GET /d2l/api/le/(version)/lti/tp/(orgUnitId)/(tpId)
31
+ # TODO: Register a new LTI tool provider for an org unit.
32
+ # => POST /d2l/api/le/(version)/lti/tp/(orgUnitId)
33
+ # TODO: Update the information associated with a registered LTI tool provider.
34
+ # => PUT /d2l/api/le/(version)/lti/tp/(tpId)
@@ -67,6 +67,26 @@ end
67
67
  # part 2: attachments
68
68
  def create_news_item(org_unit_id, news_item_data, attachments = [])
69
69
  # POST /d2l/api/le/(version)/(orgUnitId)/news/
70
+ path = "/d2l/api/le/#{$le_ver}/#{org_unit_id}/news/"
71
+ json =
72
+ {
73
+ "Title" => "Placeholder_title",
74
+ "Body" =>
75
+ { # Composite: RichText
76
+ "Text" => "plaintext_text_here",
77
+ "HTML" => nil # OR the HTML_Formatted_version_of_text
78
+ },
79
+ "StartDate" => "UTCDateTime",
80
+ "EndDate" => nil, # nil or UTCDateTime -- e.g. 2017-03-28T18:54:56.000Z
81
+ "IsGlobal" => false,
82
+ "IsPublished" => false, # sets it as a draft
83
+ "ShowOnlyInCourseOfferings" => false
84
+ }.merge!(news_item_data)
85
+ files = attachments
86
+ method = "POST"
87
+ ap json
88
+ ap _news_upload(path, json, files, method)
89
+ # RETURNS a NewsItem JSON data block
70
90
  end
71
91
 
72
92
  # NOTE: UNSTABLE!!!
@@ -0,0 +1,27 @@
1
+ require_relative 'requests'
2
+ require 'json-schema'
3
+
4
+ ########################
5
+ # ACTIONS:##############
6
+ ########################
7
+
8
+ # TODO: --UNSTABLE-- Remove the specified capability.
9
+ # => DELETE /d2l/api/lp/(version)/permissions/tools/(toolId)/capabilities/(capabilityId)
10
+ # TODO: --UNSTABLE-- Reset a permission grant to “not allowed”.
11
+ # => DELETE /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/allowed/(grantId)
12
+ # TODO: --UNSTABLE-- Retrieve all the capability grants for a tool.
13
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/capabilities/
14
+ # TODO: --UNSTABLE-- Retrieve all the permission grants for a tool’s permissions claims.
15
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/
16
+ # TODO: --UNSTABLE-- Retrieve all the allowed permission grants for a tool for a tool’s permissions claims.
17
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/allowed/
18
+ # TODO: --UNSTABLE-- Determine the allowance state of a permission grant.
19
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/allowed/(grantId)
20
+ # TODO: --UNSTABLE-- Retrieve the meta-data for all of a tool’s permission claims.
21
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/metadata/
22
+ # TODO: --UNSTABLE-- Retrieve the meta-data for one of a tool’s permission claims.
23
+ # => GET /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/metadata/(claimId)
24
+ # TODO: --UNSTABLE-- Grant a tool capability.
25
+ # => POST /d2l/api/lp/(version)/permissions/tools/(toolId)/capabilities/
26
+ # TODO: --UNSTABLE-- Set a permission grant to “allowed”.
27
+ # => PUT /d2l/api/lp/(version)/permissions/tools/(toolId)/claims/allowed/(grantId)
@@ -1,4 +1,8 @@
1
1
  require_relative 'auth'
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'mime/types'
5
+ require 'json'
2
6
 
3
7
  ########################
4
8
  # QUERIES/RESPONSE:#####
@@ -76,25 +80,231 @@ def _post(path, payload, isD2l = true)
76
80
  end
77
81
  end
78
82
  end
79
- =begin
80
- # in compliance with FTC1867 HTTP file upload
81
- def _upload(path, json, file, method, name, filename)
83
+
84
+ # NOTE: multipart code examples referrenced from danielwestendorf--
85
+ # FTC 1867 and FTC 2388 implementations are based upon the following url:
86
+ # => "https://coderwall.com/p/c-mu-a/http-posts-in-ruby"
87
+ # The code has obviously been modified for usage with basic D2L POST/PUT api methods
88
+ # in compliance with FTC 1867 & FTC 2388 HTTP file upload and according to examples
89
+ # shown on: "http://docs.valence.desire2learn.com/basic/fileupload.html"
90
+
91
+ # Upload a file to the learning repository.
92
+ def _learning_repository_upload(path, file, method)
93
+ # name = the content name,
94
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
95
+ # file = the File's name in the directory.
96
+ # method = POST or PUT
97
+ # json = the json appended to the end of the request body
98
+ auth_uri = path
99
+ auth_uri = create_authenticated_uri(path, method)
100
+ uri = URI.parse(auth_uri)
101
+
82
102
  boundary = "xxBOUNDARYxx"
83
- http_req = "Content-Type: multipart/form-data; boundary=#{boundary}\n"\
84
- "Content-Length: {#{method} #{file.bytesize}}\n\n"\
85
- "#{boundary}\n"\
86
- "Content-Type: #{content-type}\n"
87
- "Content-Disposition: form-data; name = '#{name}'; filename='#{filename}'\n"\
88
- # Requires Content-Type and boundary specification on line 1
89
- # Requires Content-Length with specification of method on line 2
90
- # Requires boundary before the content
91
- # Requires Content-Disposition, name, and filename line 1 of content
92
- # Requires Content-Type as line 2 of content
93
- # Requires boundary after the content
94
- # url, payload, {:multipart => true}, req
95
- # if sending a file, multipart is autodetected
96
- end
97
- =end
103
+ header = {"Content-Type" => "multipart/form-data; boundary=#{boundary}"}
104
+ # setup the post body
105
+ post_body = []
106
+ post_body << "--#{boundary}\n"
107
+ post_body << "Content-Disposition: form-data; name = \"Resource\"; filename=\"#{File.basename(file)}\"\r\n"
108
+ post_body << "Content-Type: application/zip\r\n\r\n"
109
+ post_body << File.read(file)
110
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
111
+
112
+ # Create the HTTP objects
113
+ http = Net::HTTP.new(uri.host, uri.port)
114
+ request = Net::HTTP::Post.new(uri.request_uri, header)
115
+ request.body = post_body.join
116
+
117
+ # Send the request
118
+ response = http.request(request)
119
+ JSON.parse(response)
120
+ end
121
+
122
+ # REVIEW: profile image upload process
123
+ def _profile_image_upload(path, file, method)
124
+ # name = the content name,
125
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
126
+ # file = the File's name in the directory.
127
+ # method = POST or PUT
128
+ # json = the json appended to the end of the request body
129
+ auth_uri = path
130
+ auth_uri = create_authenticated_uri(path, method)
131
+ uri = URI.parse(auth_uri)
132
+
133
+ boundary = "xxBOUNDARYxx"
134
+ header = {"Content-Type" => "multipart/form-data; boundary=#{boundary}"}
135
+ # setup the post body
136
+ post_body = []
137
+ post_body << "--#{boundary}\n"
138
+ post_body << "Content-Disposition: form-data; name = \"profileImage\"; filename=\"#{File.basename(file)}\"\r\n"
139
+ post_body << "Content-Type: image/png\r\n\r\n"
140
+ post_body << File.read(file)
141
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
142
+
143
+ # Create the HTTP objects
144
+ http = Net::HTTP.new(uri.host, uri.port)
145
+ request = Net::HTTP::Post.new(uri.request_uri, header)
146
+ request.body = post_body.join
147
+
148
+ # Send the request
149
+ response = http.request(request)
150
+ JSON.parse(response)
151
+ end
152
+
153
+ def _ePortfolio_upload(path, file, method, description)
154
+ # name = the content name,
155
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
156
+ # filename = the File's name in the directory.
157
+ # method = POST or PUT
158
+ # json = the json appended to the end of the request body
159
+ auth_uri = path
160
+ auth_uri = create_authenticated_uri(path, method)
161
+ uri = URI.parse(auth_uri)
162
+
163
+ boundary = "xxBOUNDARYxx"
164
+ header = {"Content-Type" => "multipart/form-data; boundary=#{boundary}"}
165
+ # setup the post body
166
+ post_body = []
167
+ post_body << "--#{boundary}\r\n"
168
+ post_body << "Content-Type: text/plain\r\n"
169
+ post_body << "Content-Disposition: form-data; name = \"name\"\r\n\r\n"
170
+ post_body << "#{File.basename(file)}\r\n"
171
+
172
+ post_body << "--#{boundary}\r\n"
173
+ post_body << "Content-Type: text/plain\r\n"
174
+ post_body << "Content-Disposition: form-data; name = \"description\"\r\n\r\n"
175
+ post_body << "#{description}\r\n"
176
+
177
+ post_body << "--#{boundary}\r\n"
178
+ post_body << "Content-Type: text/plain\r\n"
179
+ post_body << "Content-Disposition: form-data; name = \"file\"; filename=\"#{File.basename(file)}\"\r\n\r\n"
180
+ post_body << File.read(file)
181
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
182
+
183
+ # Create the HTTP objects
184
+ http = Net::HTTP.new(uri.host, uri.port)
185
+ request = Net::HTTP::Post.new(uri.request_uri, header)
186
+ request.body = post_body.join
187
+
188
+ # Send the request
189
+ response = http.request(request)
190
+ JSON.parse(response)
191
+ end
192
+
193
+ def _course_content_upload(path, json, file, method)
194
+ # name = the content name,
195
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
196
+ # filename = the File's name in the directory.
197
+ # method = POST or PUT
198
+ # json = the json appended to the end of the request body
199
+ auth_uri = path
200
+ auth_uri = create_authenticated_uri(path, method)
201
+ uri = URI.parse(auth_uri)
202
+
203
+ boundary = "xxBOUNDARYxx"
204
+ header = {"Content-Type" => "multipart/mixed; boundary=#{boundary}"}
205
+ # setup the post body
206
+ post_body = []
207
+ post_body << "--#{boundary}\r\n"
208
+ post_body << "Content-Type: application/json\r\n\r\n"
209
+
210
+ post_body << json.to_json
211
+ post_body << "\r\n"
212
+
213
+ post_body << "--#{boundary}\r\n"
214
+ post_body << "Content-Disposition: form-data; name = \"\"; filename=\"#{File.basename(file)}\"\r\n\r\n"
215
+ post_body << "Content-Type: text/plain\r\n"
216
+ post_body << File.read(file)
217
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
218
+
219
+ # Create the HTTP objects
220
+ http = Net::HTTP.new(uri.host, uri.port)
221
+ request = Net::HTTP::Post.new(uri.request_uri, header)
222
+ request.body = post_body.join
223
+
224
+ # Send the request
225
+ response = http.request(request)
226
+ JSON.parse(response)
227
+ end
228
+
229
+ def _dropbox_upload(path, json, file, method)
230
+ # name = the content name,
231
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
232
+ # filename = the File's name in the directory.
233
+ # method = POST or PUT
234
+ # json = the json appended to the end of the request body
235
+ auth_uri = path
236
+ auth_uri = create_authenticated_uri(path, method)
237
+ uri = URI.parse(auth_uri)
238
+
239
+ boundary = "xxBOUNDARYxx"
240
+ header = {"Content-Type" => "multipart/mixed; boundary=#{boundary}"}
241
+ # setup the post body
242
+ post_body = []
243
+ post_body << "--#{boundary}\r\n"
244
+ post_body << "Content-Type: application/json\r\n\r\n"
245
+
246
+ post_body << json.to_json # e.g. {"Text" => "Here you go", "Html" => null}
247
+ post_body << "\r\n"
248
+ post_body << "--#{boundary}\r\n"
249
+ post_body << "Content-Disposition: form-data; name = \"\"; filename=\"#{File.basename(file)}\"\r\n"
250
+ post_body << "Content-Type: #{MIME::Types.type_for(file)}\r\n\r\n"
251
+
252
+ post_body << File.read(file)
253
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
254
+
255
+ # Create the HTTP objects
256
+ http = Net::HTTP.new(uri.host, uri.port)
257
+ request = Net::HTTP::Post.new(uri.request_uri, header)
258
+ request.body = post_body.join
259
+
260
+ # Send the request
261
+ response = http.request(request)
262
+ JSON.parse(response)
263
+ end
264
+
265
+ # function to upload 1+ files to a news event.
266
+ # e.g. uploading 2 attachments to a news event (a text file; a png)
267
+ def _news_upload(path, json, files, method)
268
+ # name = the content name,
269
+ # e.g. "Resource", "profileImage", "name", "description", "file", "targetUsers"
270
+ # files = array of filenames
271
+ # method = POST or PUT
272
+ # json = the json appended to the end of the request body
273
+ auth_uri = path
274
+ auth_uri = create_authenticated_uri(path, method)
275
+ uri = URI.parse(auth_uri)
276
+
277
+ boundary = "xxBOUNDARYxx"
278
+ header = {"Content-Type" => "multipart/mixed; boundary=#{boundary}"}
279
+ # setup the post body
280
+ post_body = []
281
+ post_body << "--#{boundary}\r\n"
282
+ post_body << "Content-Type: application/json\r\n\r\n"
283
+
284
+ post_body << json.to_json # e.g. {"Text" => "Here you go", "Html" => null}
285
+
286
+ file_iteration = 0
287
+ files.each do |file|
288
+ post_body << "\r\n--#{boundary}\r\n"
289
+ post_body << "Content-Disposition: form-data; name = \"file #{file_iteration}\"; filename=\"#{File.basename(file)}\"\r\n"
290
+ post_body << "Content-Type: text/plain\r\n\r\n"
291
+ post_body << File.read(file)
292
+ file_iteration += 1
293
+ end
294
+ post_body << "\r\n\r\n--#{boundary}--\r\n"
295
+
296
+ # Create the HTTP objects
297
+ http = Net::HTTP.new(uri.host, uri.port)
298
+ http.set_debug_output($stdout)
299
+ http.use_ssl = true
300
+ request = Net::HTTP::Post.new(uri.request_uri, header)
301
+ request.body = post_body.join
302
+ puts request.body
303
+ # Send the request
304
+ response = http.request(request)
305
+ response.body
306
+ end
307
+
98
308
  # performs a put request using the path and the payload arguments. After first
99
309
  # creating an authenticated uri, the put request is performed using the
100
310
  # authenticated uri, the payload argument, and specifying that the payload is
@@ -1,14 +1,22 @@
1
1
  require_relative "requests"
2
2
 
3
3
  # init products to newest versions.
4
- $le_ver = get_latest_product_version('le')
5
- $lp_ver = get_latest_product_version('lp')
6
- $ep_ver = get_latest_product_version('ep')
4
+ $le_ver = get_latest_product_version('le') # learning environment
5
+ $lp_ver = get_latest_product_version('lp') # learning platform
6
+ $ep_ver = get_latest_product_version('ep') # Eportfolio
7
+ $LR_ver = get_latest_product_version('LR') # Learning repository
8
+ $bas_ver = get_latest_product_version('bas') # Award service
9
+ $lti_ver = get_latest_product_version('lti') # learning tools interoperability
10
+ # ext
11
+
7
12
  #lti, rp, LR, ext,
8
13
  puts "versions set to:"
9
14
  versions = {
10
- "le_ver" => $le_ver,
11
- "lp_ver" => $lp_ver,
12
- "ep_ver" => $ep_ver
15
+ "Learning Environment" => $le_ver,
16
+ "Learning Platform" => $lp_ver,
17
+ "Eportfolio" => $ep_ver,
18
+ "Learning Object Repository" => $LR_ver,
19
+ "Award Service" => $bas_ver,
20
+ "Learning Tools Interoperability" => $lti_ver
13
21
  }
14
22
  ap versions
@@ -212,7 +212,7 @@ def check_updated_user_data_validity(user_data)
212
212
  LastName ExternalEmail UserName
213
213
  Activation),
214
214
  'properties' => {
215
- 'OrgDefinedId' => { 'type' => 'string' },
215
+ 'OrgDefinedId' => { 'type' => %w(string null) },
216
216
  'FirstName' => { 'type' => 'string' },
217
217
  'MiddleName' => { 'type' => 'string' },
218
218
  'LastName' => { 'type' => 'string' },
@@ -279,11 +279,21 @@ def get_user_activation_settings(user_id)
279
279
  # RETURNS: a UserActivationData JSON block with the user’s current activation status.
280
280
  end
281
281
 
282
- # TODO: Update a particular user’s activation settings.
282
+ # REVIEW: Update a particular user’s activation settings.
283
283
  # RETURNS: ?
284
- def update_user_activation_settings(user_id, user_activation_data)
284
+ def update_user_activation_settings(user_id, is_active)
285
285
  # PUT /d2l/api/lp/(version)/users/(userId)/activation
286
- # RETURNS: ?
286
+ if is_active != true && is_active != false
287
+ raise ArgumentError, 'is_active is not a boolean'
288
+ else
289
+ path = "/d2l/api/lp/#{$lp_ver}/users/#{user_id}/activation"
290
+ payload =
291
+ {
292
+ "IsActive" => is_active
293
+ }
294
+ _put(path, payload)
295
+ # RETURNS: ?
296
+ end
287
297
  end
288
298
 
289
299
  ########################
@@ -291,7 +301,7 @@ end
291
301
  ########################
292
302
 
293
303
  # NOTE: UNSTABLE!
294
- # TODO: Link a user to a Google Apps user account.
304
+ # TODO: UNSTABLE!--Link a user to a Google Apps user account.
295
305
  # RETURNS: ?
296
306
  def link_user_google_apps_account(google_apps_linking_item)
297
307
  # POST /d2l/api/gae/(version)/linkuser