d2l_sdk 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a6e8ed075f1d0e73100f4d1da16fd39626b49b3
4
- data.tar.gz: 7fa70c1917e6c0a4aeb4f9cb853df0e68da0689e
3
+ metadata.gz: 88964b8ade0908b80eda0463f78cc82a18ca4c6a
4
+ data.tar.gz: 855c097579e67071038f779cee78e7b82daafddb
5
5
  SHA512:
6
- metadata.gz: 81d1fe998f56240a5af90ab20402589278ddce187048b09c16ce87454550c262e4959b1dd4d5fcec9ce6ab73d0bce65b0aa5fc468e30065866368d65b2121027
7
- data.tar.gz: 499ce6508d9320c0c3daeb4f641dee939e30dd41ebf4ff1cb811798227764357016364952e0b28930275b854d56d8e882f14a54bb5d4e4f23db9a05e26580d79
6
+ metadata.gz: f7c1ccbd845a45c2f51680e603309f5b9a72f0572b32213c6a2350012fa29331f9fed7708ea494b73df3bd356472489522b7275d06f26d863afd4006e5c0ef0d
7
+ data.tar.gz: d8476be7c9e325f11421bb91ff2cb11f1fe4622c11f026c93f5b94ece96020cf08694f30fc12f9ef2368c10ec6b3bf216a0ca8838f751d57fe9b9cebe1cc1ffd
@@ -1,16 +1,18 @@
1
- require_relative 'd2l_sdk/course_template'
2
- require_relative 'd2l_sdk/course'
3
- require_relative 'd2l_sdk/datahub'
4
- require_relative 'd2l_sdk/enroll'
5
- require_relative 'd2l_sdk/group'
6
- require_relative 'd2l_sdk/org_unit'
7
- require_relative 'd2l_sdk/section'
8
- require_relative 'd2l_sdk/semester'
9
- require_relative 'd2l_sdk/user'
10
- require_relative 'd2l_sdk/config_variables'
11
- require_relative 'd2l_sdk/demographics'
12
- require_relative 'd2l_sdk/logging'
13
- require_relative 'd2l_sdk/course_content'
14
-
1
+ require_relative 'd2l_sdk/setup_versions' # Checked
2
+ require_relative 'd2l_sdk/course_template' # Checked
3
+ require_relative 'd2l_sdk/course' # Checked
4
+ require_relative 'd2l_sdk/datahub' # Checked
5
+ require_relative 'd2l_sdk/enroll' # Checked
6
+ require_relative 'd2l_sdk/group' # Checked
7
+ require_relative 'd2l_sdk/org_unit' # Checked
8
+ require_relative 'd2l_sdk/section' # Checked
9
+ require_relative 'd2l_sdk/semester' # Checked
10
+ require_relative 'd2l_sdk/user' # Checked
11
+ require_relative 'd2l_sdk/config_variables' # Checked
12
+ require_relative 'd2l_sdk/demographics' # Checked
13
+ require_relative 'd2l_sdk/logging' # Checked
14
+ require_relative 'd2l_sdk/course_content' # Checked
15
+ require_relative 'd2l_sdk/grades' # Checked -- added 3/21
16
+ require_relative 'd2l_sdk/news' # Checked -- added 3/21
15
17
 
16
18
  puts "d2l_sdk loaded"
@@ -2,7 +2,7 @@ require 'rubygems' # useful
2
2
  require 'awesome_print' # useful for debugging
3
3
  require 'base64' # NEEDED
4
4
  require 'json' # NEEDED
5
- require 'restclient' # NEEDED
5
+ require 'rest-client' # NEEDED
6
6
  require 'openssl' # NEEDED
7
7
  require 'open-uri' # NEEDED
8
8
  require 'colorize' # useful
@@ -1,26 +1,37 @@
1
1
  require_relative 'auth'
2
2
 
3
+
4
+ @debug = false
5
+
3
6
  ########################
4
- # CONFIG VARIABLES:#####
7
+ # DEFINITIONS:##########
5
8
  ########################
6
- @debug = false
9
+ # NOTE: These provide access to the definition meta-data
10
+ # surrounding configuration variables.
7
11
 
8
- #Retrieve the definitions for all the configuration variables the user has access to view.
12
+ # Retrieve the definitions for all the configuration variables the
13
+ # user has access to view.
9
14
  def get_all_config_var_definitions(search='', bookmark='')
10
15
  path = "/d2l/api/lp/#{$lp_ver}/configVariables/definitions/"
11
16
  path += "?search=#{search}" if search != ''
12
17
  path += "?bookmark=#{bookmark}" if bookmark != ''
13
18
  _get(path)
14
- #returns paged result set of Definition JSON data blocks
19
+ # returns paged result set of Definition JSON data blocks
15
20
  end
16
21
 
17
- #Retrieve the definitions for a configuration variable.
22
+ # Retrieve the definitions for a configuration variable.
18
23
  def get_config_var_definitions(variable_id)
19
24
  path = "/d2l/api/lp/#{$lp_ver}/configVariables/(#{variable_id}/definition"
20
25
  _get(path)
21
26
  # returns Definition JSON data block
22
27
  end
23
28
 
29
+ ########################
30
+ # VALUES:###############
31
+ ########################
32
+ # NOTE: These provide access to the values assigned to configuration
33
+ # variables in the running back-end service.
34
+
24
35
  #Retrieve the value summary for a configuration variable.
25
36
  def get_config_var_values(variable_id)
26
37
  path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/values"
@@ -50,6 +61,7 @@ def get_config_var_org_unit_override_value(variable_id, org_unit_id)
50
61
  # returns OrgUnitValue JSON block
51
62
  end
52
63
 
64
+ # NOTE: UNSTABLE!!!
53
65
  # Retrieve the effective value for a configuration variable within an org unit.
54
66
  def get_config_var_org_unit_effective_value(variable_id, org_unit_id)
55
67
  path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/effectiveValues/orgUnits/#{org_unit_id}"
@@ -75,7 +87,71 @@ def get_config_var_system_value(variable_id)
75
87
  _get(path)
76
88
  end
77
89
 
90
+ # REVIEW: Set a new org value for a configuration variable.
91
+ def set_config_var_org_value(variable_id, org_value)
92
+ path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/values/org"
93
+ if org_value.is_a? String || org_value.nil?
94
+ payload = {"OrgValue" => org_value}
95
+ _put(path, payload)
96
+ else
97
+ raise ArgumentError, "Argument 'org_value' is not a String or nil"
98
+ end
99
+ end
100
+
101
+ # REVIEW: Set a new org unit override value for a configuration variable.
102
+ def set_config_var_override_value(variable_id, org_unit_id, org_unit_value)
103
+ path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/values/orgUnits/#{org_unit_id}"
104
+ if org_unit_value.is_a? String || org_unit_value.nil?
105
+ payload = {"OrgUnitValue" => org_unit_value}
106
+ _put(path, payload)
107
+ else
108
+ raise ArgumentError, "Argument 'org_unit_value' is not a String or nil"
109
+ end
110
+ end
111
+
112
+ # REVIEW: Set a new role override value for a configuration variable.
113
+ def set_config_var_role_value(variable_id, role_id, role_value)
114
+ path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/values/roles/#{role_id}"
115
+ if role_value.is_a? String || role_value.nil?
116
+ payload = {"RoleValue" => role_value}
117
+ _put(path, payload)
118
+ else
119
+ raise ArgumentError, "Argument 'role_value' is not a String or nil"
120
+ end
121
+ end
122
+
123
+ # REVIEW: Set a new system value for a configuration variable.
124
+ def set_config_var_system_value(variable_id, system_value)
125
+ path = "/d2l/api/lp/#{$lp_ver}/configVariables/#{variable_id}/values/system"
126
+ if system_value.is_a?(String) || system_value.nil?
127
+ payload = {"SystemValue" => system_value}
128
+ _put(path, payload)
129
+ else
130
+ raise ArgumentError, "Argument 'system_value' is not a String or nil"
131
+ end
132
+ end
133
+
134
+ ########################
135
+ # RESOLVER:#############
136
+ ########################
137
+ # NOTE: These provide a way to manage a configuration variable’s
138
+ # resolution strategy.
139
+
140
+ # NOTE: UNSTABLE!!!
141
+ # TODO: UNSTABLE!!! --Restore the default resolution strategy for an org unit configuration variable.
142
+ def restore_default_org_unit_config_var_resolution(variable_id)
143
+ # DELETE /d2l/api/lp/(version)/configVariables/(variableId)/resolver
144
+ end
145
+
146
+ # NOTE: UNSTABLE!!!
147
+ # REVIEW: Retrieve the resolution strategy for an org unit configuration variable.
78
148
  def get_config_var_resolver(variable_id)
79
149
  path = "/d2l/api/lp/#{lp_ver}/configVariables/#{variable_id}/resolver"
80
150
  _get(path)
81
151
  end
152
+
153
+ # NOTE: UNSTABLE!!!
154
+ # TODO: Update the resolution strategy for an org unit configuration variable.
155
+ def update_org_unit_config_var_resolution(resolver_value)
156
+ # PUT /d2l/api/lp/(version)/configVariables/(variableId)/resolver
157
+ end
@@ -1,9 +1,48 @@
1
1
  require_relative 'requests'
2
2
  require 'json-schema'
3
+
3
4
  ########################
4
- # COURSES:##############
5
+ # ACTIONS:##############
5
6
  ########################
6
7
 
8
+ # Deletes a course based, referencing it via its org_unit_id
9
+ # This reference is created through a formatted path appended with the id.
10
+ # Then, a delete http method is executed using this path, deleting the course.
11
+ def delete_course_by_id(org_unit_id)
12
+ path = "/d2l/api/lp/#{$lp_ver}/courses/#{org_unit_id}" # setup user path
13
+ #ap path
14
+ _delete(path)
15
+ puts '[+] Course data deleted successfully'.green
16
+ end
17
+
18
+ # retrieve the list of parent org unit type constraints for course offerings
19
+ def get_parent_outypes_courses_schema_constraints
20
+ path = "/d2l/api/lp/#{$lp_ver}/courses/schema"
21
+ _get(path)
22
+ # returns a JSON array of SchemaElement blocks
23
+ end
24
+
25
+ # Performs a get request to retrieve a particular course using the org_unit_id
26
+ # of this particular course. If the course does not exist, as specified by the
27
+ # org_unit_id, the response is typically a 404 error.
28
+ #
29
+ # returns: JSON object of the course
30
+ def get_course_by_id(org_unit_id)
31
+ path = "/d2l/api/lp/#{$lp_ver}/courses/#{org_unit_id}"
32
+ _get(path)
33
+ # returns: JSON object of the course
34
+ end
35
+
36
+
37
+ def get_course_image(org_unit_id, width = 0, height = 0)
38
+ path = "/d2l/api/lp/#{lp_ver}/courses/#{org_unit_id}/image"
39
+ if width > 0 && height > 0
40
+ path += "?width=#{width}"
41
+ path += "&height=#{height}"
42
+ end
43
+ _get(path)
44
+ end
45
+
7
46
  # Checks whether the created course data conforms to the valence api for the
8
47
  # course data JSON object. If it does conform, then nothing happens and it
9
48
  # simply returns true. If it does not conform, then the JSON validator raises
@@ -59,93 +98,7 @@ def create_course_data(course_data)
59
98
  # requires: CreateCourseOffering JSON block
60
99
  path = "/d2l/api/lp/#{$lp_ver}/courses/"
61
100
  _post(path, payload)
62
- puts '[+] Course creation completed successfully'.green
63
- end
64
-
65
- # In order to retrieve an entire department's class list, this method uses a
66
- # predefined org_unit identifier. This identifier is then appended to a path
67
- # and all classes withiin the department are returned as JSON objects in an arr.
68
- #
69
- # returns: JSON array of classes.
70
- def get_org_department_classes(org_unit_id)
71
- path = "/d2l/api/lp/#{$lp_ver}/orgstructure/#{org_unit_id}"
72
- _get(path)
73
- # returns: JSON array of classes.
74
- end
75
-
76
- # Performs a get request to retrieve a particular course using the org_unit_id
77
- # of this particular course. If the course does not exist, as specified by the
78
- # org_unit_id, the response is typically a 404 error.
79
- #
80
- # returns: JSON object of the course
81
- def get_course_by_id(org_unit_id)
82
- path = "/d2l/api/lp/#{$lp_ver}/courses/#{org_unit_id}"
83
- _get(path)
84
- # returns: JSON object of the course
85
- end
86
-
87
- def get_all_courses
88
- path = "/d2l/api/lp/#{$lp_ver}/orgstructure/6606/descendants/?ouTypeId=3"
89
- _get(path)
90
- end
91
-
92
- # much slower means of getting courses if less than 100 courses
93
- def get_courses_by_code(org_unit_code)
94
- all_courses = get_all_courses
95
- courses = []
96
- all_courses.each do |course|
97
- courses.push(course) if course["Code"].downcase.include? "#{org_unit_code}".downcase
98
- end
99
- courses
100
- end
101
- # Retrieves all courses that have a particular string (org_unit_name) within
102
- # their names. This is done by first defining that none are found yet and then
103
- # searching through all course for ones that do have a particular string within
104
- # their name, the matches are pushed into the previously empty array of matches.
105
- # This array is subsequently returned; if none were found, a message is returned
106
- #
107
- # returns: JSON array of matching course data objects
108
- def get_courses_by_name(org_unit_name)
109
- get_courses_by_property_by_string('Name', org_unit_name)
110
- end
111
-
112
- # Retrieves all matching courses that are found using a property and a search
113
- # string. First, it is considered that the class is not found. Then, all courses
114
- # are retrieved and stored as a JSON array in the varaible +results+. After this
115
- # each of the +results+ is iterated, downcased, and checked for their matching
116
- # of the particular search string. If there is a match, they are pushed to
117
- # an array called +courses_results+. This is returned at the end of this op.
118
- #
119
- # returns: array of JSON course objects (that match the search string/property)
120
- def get_courses_by_property_by_string(property, search_string)
121
- puts "[+] Searching for courses using search string: #{search_string}".yellow +
122
- + " -- And property: #{property}"
123
- courses_results = []
124
- results = get_all_courses
125
- results.each do |x|
126
- if x[property].downcase.include? search_string.downcase
127
- courses_results.push(x)
128
- end
129
- end
130
- courses_results
131
- # returns array of all matching courses in JSON format.
132
- end
133
-
134
- # Retrieves all courses that have the specified prop match a regular expression.
135
- # This is done by iterating through all courses and returning an array of all
136
- # that match a regular expression.
137
- #
138
- # returns: array of JSON course objects (with property that matches regex)
139
- def get_courses_by_property_by_regex(property, regex)
140
- puts "[+] Searching for courses using regex: #{regex}".yellow +
141
- + " -- And property: #{property}"
142
- courses_results = []
143
- results = get_all_courses
144
- results.each do |x|
145
- courses_results.push(x) if (x[property] =~ regex) != nil
146
- end
147
- courses_results
148
- # returns array of all matching courses in JSON format.
101
+ #puts '[+] Course creation completed successfully'.green
149
102
  end
150
103
 
151
104
  # Checks whether the updated course data conforms to the valence api for the
@@ -192,16 +145,30 @@ def update_course_data(course_id, new_data)
192
145
  # Provide feedback that the update was successful
193
146
  end
194
147
 
195
- def is_course_component(key)
196
- valid_components = %w(AttendanceRegisters Glossary News Checklists
197
- Grades QuestionLibrary Competencies GradesSettings
198
- Quizzes Content Groups ReleaseConditions CourseFiles
199
- Homepages Rubrics Discussions IntelligentAgents
200
- Schedule DisplaySettings Links SelfAssessments
201
- Dropbox LtiLink Surveys Faq LtiTP ToolNames Forms
202
- Navbars Widgets)
203
- valid_components.include?(key)
204
- # returns whether the key is actually a course component
148
+ # TODO: Update the course image for a course offering.
149
+ def update_course_image(org_unit_id, image_file)
150
+ # PUT /d2l/api/lp/(version)/courses/(orgUnitId)/image
151
+ end
152
+
153
+ ########################
154
+ # COURSE TEMPLATES:#####
155
+ ########################
156
+ # NOTE: Course template related functions are now in 'course_template.rb'
157
+
158
+ ########################
159
+ # COPYING COURSES:######
160
+ ########################
161
+
162
+ def get_copy_job_request_status(org_unit_id, job_token)
163
+ path = "/d2l/api/le/#{le_ver}/import/#{org_unit_id}/copy/#{job_token}"
164
+ _get(path)
165
+ # returns GetCopyJobResponse JSON block
166
+ # GetImportJobResponse:
167
+ # {"JobToken" => <string:COPYJOBSTATUS_T>,
168
+ # "TargetOrgUnitID" => <number:D2LID>,
169
+ # "Status" => <string:IMPORTJOBTSTATUS_T>}
170
+ # States of getImport: UPLOADING, PROCESSING, PROCESSED, IMPORTING,
171
+ # IMPORTFAILED, COMPLETED
205
172
  end
206
173
 
207
174
  def check_create_copy_job_request_validity(create_copy_job_request)
@@ -223,6 +190,19 @@ def check_create_copy_job_request_validity(create_copy_job_request)
223
190
  JSON::Validator.validate!(schema, create_copy_job_request, validate_schema: true)
224
191
  end
225
192
 
193
+ # simple schema check to assure the course component is an actual course component
194
+ # returns: boolean
195
+ def is_course_component(key)
196
+ valid_components = %w(AttendanceRegisters Glossary News Checklists
197
+ Grades QuestionLibrary Competencies GradesSettings
198
+ Quizzes Content Groups ReleaseConditions CourseFiles
199
+ Homepages Rubrics Discussions IntelligentAgents
200
+ Schedule DisplaySettings Links SelfAssessments
201
+ Dropbox LtiLink Surveys Faq LtiTP ToolNames Forms
202
+ Navbars Widgets)
203
+ valid_components.include?(key)
204
+ # returns whether the key is actually a course component
205
+ end
226
206
 
227
207
  def create_new_copy_job_request(org_unit_id, create_copy_job_request)
228
208
  payload =
@@ -247,27 +227,26 @@ def create_new_copy_job_request(org_unit_id, create_copy_job_request)
247
227
  # Returns CreateCopyJobResponse JSON block
248
228
  end
249
229
 
250
- def get_copy_job_request_status(org_unit_id, job_token)
251
- path = "/d2l/api/le/#{le_ver}/import/#{org_unit_id}/copy/#{job_token}"
252
- _get(path)
253
- # returns GetCopyJobResponse JSON block
254
- # GetImportJobResponse:
255
- # {"JobToken" => <string:COPYJOBSTATUS_T>,
256
- # "TargetOrgUnitID" => <number:D2LID>,
257
- # "Status" => <string:IMPORTJOBTSTATUS_T>}
258
- # States of getImport: UPLOADING, PROCESSING, PROCESSED, IMPORTING,
259
- # IMPORTFAILED, COMPLETED
230
+ # NOTE: UNSTABLE!!!!
231
+ # TODO: --UNSTABLE-- Retrieve the list of logs for course copy jobs.
232
+ # Query Params:
233
+ # --OPTIONAL--
234
+ # -bookmark : string
235
+ # -page_size : number
236
+ # -source_org_unit_id : number
237
+ # -destination_org_unit_id : number
238
+ # -start_date : UTCDateTime
239
+ # -end_date : UTCDateTime
240
+ # RETURNS: An object list page containing the resulting CopyCourseLogMessage data blocks
241
+ def get_copy_jobs_logs(bookmark = '', page_size = 0, source_org_unit_id = 0,
242
+ destination_org_unit_id = 0, start_date = '', end_date = '')
243
+ # GET /d2l/api/le/(version)/ccb/logs
260
244
  end
261
- #########
262
- =begin
263
- def create_course_import_request(org_unit_id, callback_url = '')
264
- path = "/d2l/le/#{le_ver}/import/#{org_unit_id}/imports/"
265
- path += "?callbackUrl=#{callback_url}" if callback_url != ''
266
- #_post(path, payload)
267
- #_upload(path, json, file, 'POST', 'file', filename)
268
245
 
269
- end
270
- =end
246
+ ########################
247
+ # IMPORTING COURSES:####
248
+ ########################
249
+
271
250
  def get_course_import_job_request_status(org_unit_id, job_token)
272
251
  path = "/d2l/api/le/#{le_ver}/import/#{org_unit_id}/imports/#{job_token}"
273
252
  _get(path)
@@ -284,28 +263,97 @@ def get_course_import_job_request_logs(org_unit_id, job_token, bookmark = '')
284
263
  # returns PAGED RESULT of ImportCourseLog JSON blocks following bookmark param
285
264
  end
286
265
 
287
- # Deletes a course based, referencing it via its org_unit_id
288
- # This reference is created through a formatted path appended with the id.
289
- # Then, a delete http method is executed using this path, deleting the course.
290
- def delete_course_by_id(org_unit_id)
291
- path = "/d2l/api/lp/#{$lp_ver}/courses/#{org_unit_id}" # setup user path
292
- #ap path
293
- _delete(path)
294
- puts '[+] Course data deleted successfully'.green
266
+ # TODO: Create a new course import job request.
267
+ # INPUT: simple file upload process
268
+ def create_course_import_request(org_unit_id, callback_url = '')
269
+ #path = "/d2l/le/#{le_ver}/import/#{org_unit_id}/imports/"
270
+ #path += "?callbackUrl=#{callback_url}" if callback_url != ''
271
+ #_post(path, payload)
272
+ #_upload(path, json, file, 'POST', 'file', filename)
295
273
  end
296
274
 
297
- # retrieve the list of parent org unit type constraints for course offerings
298
- def get_parent_outypes_courses_schema_constraints
299
- path = "/d2l/api/lp/#{$lp_ver}/courses/schema"
300
- _get(path)
301
- # returns a JSON array of SchemaElement blocks
275
+ ################################################################################
276
+ ################################################################################
277
+
278
+
279
+ ###########################
280
+ # ADDITIONAL FUNCTIONS:####
281
+ ###########################
282
+
283
+
284
+ # In order to retrieve an entire department's class list, this method uses a
285
+ # predefined org_unit identifier. This identifier is then appended to a path
286
+ # and all classes withiin the department are returned as JSON objects in an arr.
287
+ #
288
+ # returns: JSON array of classes.
289
+ def get_org_department_classes(org_unit_id)
290
+ path = "/d2l/api/lp/#{$lp_ver}/orgstructure/#{org_unit_id}"
291
+ _get(path)
292
+ # returns: JSON array of classes.
302
293
  end
303
294
 
304
- def get_course_image(org_unit_id, width = 0, height = 0)
305
- path = "/d2l/api/lp/#{lp_ver}/courses/#{org_unit_id}/image"
306
- if width > 0 && height > 0
307
- path += "?width=#{width}"
308
- path += "&height=#{height}"
295
+
296
+
297
+ def get_all_courses
298
+ path = "/d2l/api/lp/#{$lp_ver}/orgstructure/6606/descendants/?ouTypeId=3"
299
+ _get(path)
300
+ end
301
+
302
+ # much slower means of getting courses if less than 100 courses
303
+ def get_courses_by_code(org_unit_code)
304
+ all_courses = get_all_courses
305
+ courses = []
306
+ all_courses.each do |course|
307
+ courses.push(course) if course["Code"].downcase.include? "#{org_unit_code}".downcase
309
308
  end
310
- _get(path)
309
+ courses
310
+ end
311
+ # Retrieves all courses that have a particular string (org_unit_name) within
312
+ # their names. This is done by first defining that none are found yet and then
313
+ # searching through all course for ones that do have a particular string within
314
+ # their name, the matches are pushed into the previously empty array of matches.
315
+ # This array is subsequently returned; if none were found, a message is returned
316
+ #
317
+ # returns: JSON array of matching course data objects
318
+ def get_courses_by_name(org_unit_name)
319
+ get_courses_by_property_by_string('Name', org_unit_name)
320
+ end
321
+
322
+ # Retrieves all matching courses that are found using a property and a search
323
+ # string. First, it is considered that the class is not found. Then, all courses
324
+ # are retrieved and stored as a JSON array in the varaible +results+. After this
325
+ # each of the +results+ is iterated, downcased, and checked for their matching
326
+ # of the particular search string. If there is a match, they are pushed to
327
+ # an array called +courses_results+. This is returned at the end of this op.
328
+ #
329
+ # returns: array of JSON course objects (that match the search string/property)
330
+ def get_courses_by_property_by_string(property, search_string)
331
+ puts "[+] Searching for courses using search string: #{search_string}".yellow +
332
+ + " -- And property: #{property}"
333
+ courses_results = []
334
+ results = get_all_courses
335
+ results.each do |x|
336
+ if x[property].downcase.include? search_string.downcase
337
+ courses_results.push(x)
338
+ end
339
+ end
340
+ courses_results
341
+ # returns array of all matching courses in JSON format.
342
+ end
343
+
344
+ # Retrieves all courses that have the specified prop match a regular expression.
345
+ # This is done by iterating through all courses and returning an array of all
346
+ # that match a regular expression.
347
+ #
348
+ # returns: array of JSON course objects (with property that matches regex)
349
+ def get_courses_by_property_by_regex(property, regex)
350
+ puts "[+] Searching for courses using regex: #{regex}".yellow +
351
+ + " -- And property: #{property}"
352
+ courses_results = []
353
+ results = get_all_courses
354
+ results.each do |x|
355
+ courses_results.push(x) if (x[property] =~ regex) != nil
356
+ end
357
+ courses_results
358
+ # returns array of all matching courses in JSON format.
311
359
  end