d2l_sdk 0.1.7
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 +7 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +204 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/d2l_sdk.gemspec +42 -0
- data/example_scripts/adjusted_courses.txt +44446 -0
- data/example_scripts/fix_201708_courses.rb +13 -0
- data/example_scripts/update_enddates.rb +88 -0
- data/lib/d2l_sdk.rb +16 -0
- data/lib/d2l_sdk/auth.rb +95 -0
- data/lib/d2l_sdk/config.rb +56 -0
- data/lib/d2l_sdk/config_variables.rb +81 -0
- data/lib/d2l_sdk/course.rb +311 -0
- data/lib/d2l_sdk/course_content.rb +362 -0
- data/lib/d2l_sdk/course_template.rb +179 -0
- data/lib/d2l_sdk/datahub.rb +213 -0
- data/lib/d2l_sdk/demographics.rb +89 -0
- data/lib/d2l_sdk/enroll.rb +133 -0
- data/lib/d2l_sdk/group.rb +232 -0
- data/lib/d2l_sdk/logging.rb +57 -0
- data/lib/d2l_sdk/news.rb +20 -0
- data/lib/d2l_sdk/org_unit.rb +383 -0
- data/lib/d2l_sdk/requests.rb +241 -0
- data/lib/d2l_sdk/section.rb +207 -0
- data/lib/d2l_sdk/semester.rb +159 -0
- data/lib/d2l_sdk/user.rb +420 -0
- data/lib/d2l_sdk/version.rb +3 -0
- metadata +228 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
require_relative 'requests'
|
|
2
|
+
require 'json-schema'
|
|
3
|
+
require 'zip'
|
|
4
|
+
require 'csv'
|
|
5
|
+
##########################
|
|
6
|
+
# DATA HUB Import/Export##
|
|
7
|
+
##########################
|
|
8
|
+
|
|
9
|
+
# Requirements to work properly:
|
|
10
|
+
# !!! 1. Custom Reporting Framework must be on
|
|
11
|
+
# --- Organization Tools > Custom Reporting Framework > Click "Availability" Slider
|
|
12
|
+
# --- This should have enabled it, otherwise you may need further permissions
|
|
13
|
+
# !!! 2. Next, the API user must have the permissions
|
|
14
|
+
# --- Roles and Permissions > ROLE > Filter by 'Custom Reporting Framework' >
|
|
15
|
+
# --- Enable all reports you need.
|
|
16
|
+
# !!! 3. EACH data set has its own permissions. These must be enabled.
|
|
17
|
+
# --- The Insights tool must be on, this can be checked at:
|
|
18
|
+
# ----- "Config variable browser" > tools > insights > ETL > isEnabled
|
|
19
|
+
# ----- If the value is 0, then you must contact support to enable it
|
|
20
|
+
# ----- If the value is 1, then move onto the next sub-step
|
|
21
|
+
# --- Roles and Permissions > ROLES> Filter by 'Insights' > Enable "Can Export
|
|
22
|
+
# --- Data Warehouse Reports" permission
|
|
23
|
+
|
|
24
|
+
# Lists all available data sets
|
|
25
|
+
def get_all_data_sets
|
|
26
|
+
_get("/d2l/api/lp/#{$lp_ver}/dataExport/list")
|
|
27
|
+
# returns a JSON array of DataSetData blocks
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Retrieve a data set
|
|
31
|
+
def get_data_set(data_set_id)
|
|
32
|
+
_get("/d2l/api/lp/#{$lp_ver}/dataExport/list/#{data_set_id}")
|
|
33
|
+
# returns a DataSetData JSON block
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# assures that the CreateExportJobData JSON block is valid based off of a
|
|
37
|
+
# specified JSON schema.
|
|
38
|
+
# filter names: startDate, endDate, roles, and parentOrgUnitId
|
|
39
|
+
# --- startDate and EndDate must be UTC dates
|
|
40
|
+
# --- parentOrgUnitId and roles are integers corresponding to an ou_id & role_id
|
|
41
|
+
def validate_create_export_job_data(create_export_job_data)
|
|
42
|
+
schema = {
|
|
43
|
+
'type' => 'object',
|
|
44
|
+
# 'title'=>'the CreateExportJobData JSON block',
|
|
45
|
+
'required' => %w(DataSetId Filters),
|
|
46
|
+
'properties' => {
|
|
47
|
+
'DataSetId' => { 'type' => 'string' },
|
|
48
|
+
'Filters' => { # define the filter array
|
|
49
|
+
# 'description' => 'The array of filters for CreateExportJobData',
|
|
50
|
+
'type' => 'array',
|
|
51
|
+
'items' =>
|
|
52
|
+
{
|
|
53
|
+
'type' => "object",
|
|
54
|
+
"properties" => {
|
|
55
|
+
"Name" => {'type'=>"string"},
|
|
56
|
+
"Value" => {'type'=>"string"}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
#ap schema
|
|
63
|
+
JSON::Validator.validate!(schema, create_export_job_data, validate_schema: true)
|
|
64
|
+
# returns true if the CreateExportJobData JSON block is valid
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Create an export job for the requested data set
|
|
68
|
+
def create_export_job(create_export_job_data)
|
|
69
|
+
# init payload and merge with export job data
|
|
70
|
+
payload = {
|
|
71
|
+
'DataSetId' => '',
|
|
72
|
+
'Filters' => [] # {"Name"=> "startDate", "Value" => UTCDATETIME STRING}
|
|
73
|
+
}.merge!(create_export_job_data)
|
|
74
|
+
validate_create_export_job_data(payload)
|
|
75
|
+
# Requires: CreateExportJobData JSON parameter
|
|
76
|
+
path = "/d2l/api/lp/#{$lp_ver}/dataExport/create"
|
|
77
|
+
_post(path, payload)
|
|
78
|
+
# returns ExportJobData JSON block
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# List all available export jobs that you have previously submitted
|
|
82
|
+
def get_all_export_jobs(bookmark = '') # optional parameter page -- integer
|
|
83
|
+
path = "/d2l/api/lp/#{$lp_ver}/dataExport/jobs"
|
|
84
|
+
path += "?bookmark=#{bookmark}" if bookmark != ''
|
|
85
|
+
_get(path)
|
|
86
|
+
# returns: JSON array of paged ExportJobData blocks, sorted by SubmitDate
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Retrieves information about a data export job that you have previously submitted.
|
|
90
|
+
def get_data_export_job(export_job_id)
|
|
91
|
+
_get("/d2l/api/lp/#{$lp_ver}/dataExport/jobs/#{export_job_id}")
|
|
92
|
+
# returns: ExportJobData JSON block
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_job_status_code(export_job_id)
|
|
96
|
+
get_data_export_job(export_job_id)["Status"] #if 2 is OKAY/COMPLETED
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Downloads the identified job and stores the zip within the working directory
|
|
100
|
+
# Extracts zipped job contents in "export_jobs" folder of working directory
|
|
101
|
+
def download_job_csv(export_job_id)
|
|
102
|
+
attempt = 0
|
|
103
|
+
puts "Attempting to download job: #{export_job_id}"
|
|
104
|
+
while attempt < 20 # Attempts 20 times (~3 mins) unless job failed.
|
|
105
|
+
status = get_job_status_code(export_job_id)
|
|
106
|
+
case status
|
|
107
|
+
when 2 # If the status was okay, break loop + return download of job
|
|
108
|
+
zip_fname = 'export1.zip'
|
|
109
|
+
puts "Job complete, writing to zip: #{zip_fname}"
|
|
110
|
+
File.write(zip_fname,_get_raw("/d2l/api/lp/#{$lp_ver}/dataExport/download/#{export_job_id}"))
|
|
111
|
+
unzip(zip_fname, /sec_|off_/) # unzip file; filter if Enrollments + CSV
|
|
112
|
+
puts "file downloaded and unzipped"
|
|
113
|
+
break
|
|
114
|
+
when /3|4/
|
|
115
|
+
puts "Job download failed due to status: #{status}"
|
|
116
|
+
if status == 3
|
|
117
|
+
puts "Status description: Error - An error occurred when processing the export"
|
|
118
|
+
else
|
|
119
|
+
puts "Status description: Deleted - File was deleted from file system"
|
|
120
|
+
end
|
|
121
|
+
break
|
|
122
|
+
else # else, print out the status and wait 10 seconds before next attempt
|
|
123
|
+
puts "The job is not currently ready to download\n Status Code: #{status}"
|
|
124
|
+
if status == 0
|
|
125
|
+
puts "Status description: Queued - Export job has been received for processing."
|
|
126
|
+
else
|
|
127
|
+
puts "Status description: Processing - Currently in process of exporting data set."
|
|
128
|
+
end
|
|
129
|
+
puts "Sleeping for 10 seconds.."
|
|
130
|
+
sleep 10
|
|
131
|
+
attempt = attempt + 1
|
|
132
|
+
end
|
|
133
|
+
# returns: ZIP file containing a CSV file of data from the export job
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Unzip the file, applying a regex filter to the CSV if
|
|
138
|
+
# the file is Enrollments data.
|
|
139
|
+
def unzip(file_path, csv_filter = //)
|
|
140
|
+
puts "Unzipping file: #{file_path}"
|
|
141
|
+
# Unzip the file
|
|
142
|
+
Zip::File.open(file_path) { |zip_file|
|
|
143
|
+
# for each file in the zip file
|
|
144
|
+
zip_file.each { |f|
|
|
145
|
+
# create file path of export_jobs/#{f.name}
|
|
146
|
+
f_path=File.join("export_jobs", f.name)
|
|
147
|
+
# make the directory if not already made
|
|
148
|
+
FileUtils.mkdir_p(File.dirname(f_path))
|
|
149
|
+
# extract the file unless the file already exists
|
|
150
|
+
zip_file.extract(f, f_path) unless File.exist?(f_path)
|
|
151
|
+
# if the file is CSV and Enrollments, apply filters and proper
|
|
152
|
+
# CSV formatting to the file, writing it as base f.name + filtered.csv
|
|
153
|
+
if (f.name.include? ".csv") && (f.name.include? "Enrollments")
|
|
154
|
+
filter_formatted_enrollments("export_jobs/#{f.name}", csv_filter, "export_jobs/instr.csv")
|
|
155
|
+
end
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Get all 'current' courses, assuming all instr courses are current
|
|
161
|
+
# and add their sec/off course_term_star_num codes to a set.
|
|
162
|
+
# return: set of current classes formatted as "#{course_term}_#{star_number}"
|
|
163
|
+
def get_current_courses(csv_fname)
|
|
164
|
+
puts "Retrieving current courses from #{csv_fname}"
|
|
165
|
+
instr_courses = Set.new
|
|
166
|
+
CSV.foreach(csv_fname, :headers => true) do |row|
|
|
167
|
+
star_number = row[0]
|
|
168
|
+
course_term = row[10]
|
|
169
|
+
instr_courses.add("#{course_term}_#{star_number}")
|
|
170
|
+
end
|
|
171
|
+
instr_courses
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Filter all enrollments and withdrawals in a csv file, excluding data
|
|
175
|
+
# that is not properly formatted (based on ou code), not a current or
|
|
176
|
+
# future course, or nil for their ou code.
|
|
177
|
+
def filter_formatted_enrollments(csv_fname, regex_filter = //, instr_fname)
|
|
178
|
+
# Create csv with 'filtered' pre-appended to '.csv' substring
|
|
179
|
+
filtered_csv = csv_fname.gsub(/\.csv/,"filtered.csv")
|
|
180
|
+
File.open(filtered_csv, 'w') do |file|
|
|
181
|
+
# set row num to 0 to keep track of headers
|
|
182
|
+
row_num = 0
|
|
183
|
+
current = get_current_courses(instr_fname)
|
|
184
|
+
# for each row
|
|
185
|
+
puts "Filtering #{csv_fname}"
|
|
186
|
+
CSV.foreach(csv_fname) do |row|
|
|
187
|
+
# the line is initialized as an empty string
|
|
188
|
+
line = ""
|
|
189
|
+
# Skip the row if not a valid
|
|
190
|
+
# or skip in-filter OU_code,
|
|
191
|
+
# or skip if the header
|
|
192
|
+
# or skip if not within the INSTR SET of current/future courses
|
|
193
|
+
if row[3] == nil || row_num > 0 && !(row[3] =~ regex_filter) || (!current.include? row[3][4..-1])
|
|
194
|
+
row_num += 1
|
|
195
|
+
next
|
|
196
|
+
end
|
|
197
|
+
# for values not filtered from above ^
|
|
198
|
+
# for all of these values
|
|
199
|
+
row[0..-1].each do |value|
|
|
200
|
+
# If it a UTC date time value, then parse as Time.
|
|
201
|
+
if value =~ /\b[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]*Z\b/ # if the value is UTC formatted
|
|
202
|
+
line << "\"#{Time.parse(value)}\""
|
|
203
|
+
elsif value == row[-1]# if its the last value in the row
|
|
204
|
+
line <<"\"#{value}\"" # then dont put a comma at the end.
|
|
205
|
+
else # not the last value in the row,
|
|
206
|
+
line << "\"#{value}\"," # throw a comma after the value
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
file.write(line + "\n") # append this line to the csv
|
|
210
|
+
row_num += 1 # increment the row number
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require_relative 'requests'
|
|
2
|
+
require 'json-schema'
|
|
3
|
+
|
|
4
|
+
########################
|
|
5
|
+
# DEMOGRPAHICS:#########
|
|
6
|
+
########################
|
|
7
|
+
|
|
8
|
+
###### Actions
|
|
9
|
+
|
|
10
|
+
# Delete one or more of a particular user's associated demographics entries.
|
|
11
|
+
# if no entries specified, it DELETES ALL.
|
|
12
|
+
# entry_ids are added as additional variables
|
|
13
|
+
# entry_ids is a CSV formatted string
|
|
14
|
+
def delete_user_demographics(user_id, entry_ids = '')
|
|
15
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/users/#{user_id}"
|
|
16
|
+
path += "?entryIds=" + entry_ids if entry_ids != ''
|
|
17
|
+
_delete(path)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# optional params: fieldIds, roleIds, and userIds are CSV formatted Strings
|
|
21
|
+
# search and bookmark are Strings
|
|
22
|
+
# retrieve all the demographics entries for all users enrolled in an OU
|
|
23
|
+
def get_all_demographics_by_org_unit(org_unit_id, field_ids = '', role_ids = '',
|
|
24
|
+
user_ids = '', search = '', bookmark = '')
|
|
25
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/orgUnits/#{org_unit_id}/users/"
|
|
26
|
+
path += "?fieldIds=" + field_ids if field_ids != ''
|
|
27
|
+
path += "?roleIds=" + role_ids if role_ids != ''
|
|
28
|
+
path += "?userIds=" + user_ids if user_ids != ''
|
|
29
|
+
path += "?search=" + search if search != ''
|
|
30
|
+
path += "?bookmark=" + bookmark if bookmark != ''
|
|
31
|
+
_get(path)
|
|
32
|
+
# returns paged result set of DemographicsUserEntryData JSON blocks
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# retrieve all the demographics entries for a specific user within an OU
|
|
36
|
+
def get_all_demographics_by_org_unit_by_user(org_unit_id, user_id, field_ids = '')
|
|
37
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/orgUnits/#{org_unit_id}/users/(#{user_id})"
|
|
38
|
+
path += "#{field_ids}" if field_ids != ''
|
|
39
|
+
_get(path)
|
|
40
|
+
# returns DemographicsUserEntryData JSON block
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# retrieve all demographics entries for all users with specified filters
|
|
44
|
+
def get_all_demographics(field_ids = '', role_ids = '', user_ids = '',
|
|
45
|
+
search = '', bookmark = '')
|
|
46
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/users/"
|
|
47
|
+
path += "#{field_ids}" if field_ids != ''
|
|
48
|
+
path += "#{role_ids}" if role_ids != ''
|
|
49
|
+
path += "#{user_ids}" if user_ids != ''
|
|
50
|
+
path += "#{search}" if search != ''
|
|
51
|
+
path += "#{bookmark}" if bookmark != ''
|
|
52
|
+
_get(path)
|
|
53
|
+
# returns paged result set of DemographicsUserEntryData JSON blocks
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
###### FIELDS
|
|
58
|
+
# retrieve list of all demographics fields
|
|
59
|
+
def get_all_demographic_fields(bookmark = '')
|
|
60
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/fields/"
|
|
61
|
+
path += "#{bookmark}" if bookmark != ''
|
|
62
|
+
_get(path)
|
|
63
|
+
# returns paged result set of DemographicsField JSON blocks
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# retrieve a single demographic field
|
|
67
|
+
def get_demographic_field(field_id)
|
|
68
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/fields/#{field_id}"
|
|
69
|
+
_get(path)
|
|
70
|
+
# returns fetch form of DemographicsField JSON block
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
###### DATA TYPES
|
|
74
|
+
|
|
75
|
+
# retrieve the list of all demographics data types
|
|
76
|
+
# uses DataTypeId's as a paging control value
|
|
77
|
+
def get_all_demographic_types(bookmark = '')
|
|
78
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/dataTypes/"
|
|
79
|
+
path += "#{bookmark}" if bookmark != ''
|
|
80
|
+
_get(path)
|
|
81
|
+
# returns paged result set of DemographicsDataType JSON blocks
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# retrieve a single demographic data type
|
|
85
|
+
def get_demographic_type(data_type_id)
|
|
86
|
+
path = "/d2l/api/lp/#{$lp_ver}/demographics/dataTypes/#{data_type_id}"
|
|
87
|
+
_get(path)
|
|
88
|
+
# returns DemographicsDataType JSON block
|
|
89
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require_relative 'requests'
|
|
2
|
+
require 'json-schema'
|
|
3
|
+
########################
|
|
4
|
+
# Enrollments:##########
|
|
5
|
+
########################
|
|
6
|
+
|
|
7
|
+
# Check the validity of the CreateEnrollmentData that is passed as a payload
|
|
8
|
+
def check_create_enrollment_data_validity(enrollment_data)
|
|
9
|
+
schema = {
|
|
10
|
+
'type' => 'object',
|
|
11
|
+
'required' => %w(OrgUnitId UserId RoleId),
|
|
12
|
+
'properties' => {
|
|
13
|
+
'OrgUnitId' => { 'type' => 'integer' },
|
|
14
|
+
'UserId' => { 'type' => 'integer' },
|
|
15
|
+
'RoleId' => { 'type' => 'integer' },
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
JSON::Validator.validate!(schema, enrollment_data, validate_schema: true)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Create a new enrollment for a user.
|
|
22
|
+
def create_user_enrollment(course_enrollment_data)
|
|
23
|
+
payload = { 'OrgUnitId' => '', # String
|
|
24
|
+
'UserId' => '', # String
|
|
25
|
+
'RoleId' => '', # String
|
|
26
|
+
}.merge!(course_enrollment_data)
|
|
27
|
+
# ap payload
|
|
28
|
+
# requires: CreateEnrollmentData JSON block
|
|
29
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/"
|
|
30
|
+
_post(path, payload)
|
|
31
|
+
puts '[+] User successfully enrolled'.green
|
|
32
|
+
# Returns: EnrollmentData JSON block for the newly enrolled user.
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Retrieve enrollment details in an org unit for the provided user.
|
|
36
|
+
# Same as +get_org_unit_enrollment_data_by_user+
|
|
37
|
+
def get_user_enrollment_data_by_org_unit(user_id, org_unit_id)
|
|
38
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/users/#{user_id}/orgUnits/#{org_unit_id}"
|
|
39
|
+
_get(path)
|
|
40
|
+
# Returns: EnrollmentData JSON block.
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Retrieve a list of all enrollments for the provided user.
|
|
44
|
+
# Optional params:
|
|
45
|
+
# --orgUnitTypeId (CSV of D2LIDs)
|
|
46
|
+
# --roleId: D2LIDs
|
|
47
|
+
# --bookmark: string
|
|
48
|
+
def get_all_enrollments_of_user(user_id, org_unit_type_id = 0, role_id = 0,
|
|
49
|
+
bookmark = '')
|
|
50
|
+
path = "/d2l/api/lp/1.3/enrollments/users/#{user_id}/orgUnits/"
|
|
51
|
+
path += "?orgUnitTypeId=#{org_unit_type_id}" if org_unit_type_id != 0
|
|
52
|
+
path += "?roleId=#{role_id}" if role_id != 0
|
|
53
|
+
path += "?bookmark=#{bookmark}" if bookmark != ''
|
|
54
|
+
_get(path)
|
|
55
|
+
# Returns: paged result set w/ the resulting UserOrgUnit data blocks
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Retrieve enrollment details for a user in the provided org unit.
|
|
59
|
+
# Note:
|
|
60
|
+
# Same as +get_user_enrollment_data_by_org_unit+
|
|
61
|
+
# This call is equivalent to the route that fetches by specifying the user first,
|
|
62
|
+
# and then the org unit.
|
|
63
|
+
def get_org_unit_enrollment_data_by_user(org_unit_id, user_id)
|
|
64
|
+
path = "/d2l/api/lp/#{$lp_ver}/orgUnits/#{org_unit_id}/users/#{user_id}"
|
|
65
|
+
_get(path)
|
|
66
|
+
# Returns: EnrollmentData JSON block.
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Retrieve the collection of users enrolled in the identified org unit.
|
|
70
|
+
# Optional params:
|
|
71
|
+
# --roleId: D2LID
|
|
72
|
+
# --bookmark: String
|
|
73
|
+
def get_org_unit_enrollments(org_unit_id, role_id = 0, bookmark = '')
|
|
74
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/orgUnits/#{org_unit_id}/users/"
|
|
75
|
+
path += "?roleId=#{role_id}" if role_id != 0
|
|
76
|
+
path += "?bookmark=#{bookmark}" if bookmark != ''
|
|
77
|
+
_get(path)
|
|
78
|
+
# Returns: paged result set containing the resulting OrgUnitUser data blocks
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Retrieve the enrollment details for the current user in the provided org unit.
|
|
82
|
+
def get_enrollments_details_of_current_user
|
|
83
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/myenrollments/org_unit_id/"
|
|
84
|
+
_get(path)
|
|
85
|
+
# Returns: MyOrgUnitInfo JSON block.
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Retrieve the list of all enrollments for the current user
|
|
89
|
+
# Optional params:
|
|
90
|
+
# --orgUnitTypeId: CSV of D2LIDs
|
|
91
|
+
# --bookmark: String
|
|
92
|
+
# --sortBy: string
|
|
93
|
+
# --isActive: bool
|
|
94
|
+
# --startDateTime: UTCDateTime
|
|
95
|
+
# --endDateTime: UTCDateTime
|
|
96
|
+
# --canAccess: bool
|
|
97
|
+
def get_all_enrollments_of_current_user(bookmark = '', sort_by = '', is_active = nil,
|
|
98
|
+
start_date_time = '', end_date_time = '',
|
|
99
|
+
can_access = nil)
|
|
100
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/myenrollments/"
|
|
101
|
+
path += "?bookmark=#{bookmark}" if bookmark != ''
|
|
102
|
+
path += "?sortBy=#{sort_by}" if sort_by != ''
|
|
103
|
+
path += "?isActive=#{is_active}" if is_active != nil
|
|
104
|
+
path += "?startDateTime=#{start_date_time}" if start_date_time != ''
|
|
105
|
+
path += "?endDateTime=#{end_date_time}" if end_date_time != ''
|
|
106
|
+
path += "?canAccess=#{can_access}" if can_access != nil
|
|
107
|
+
_get(path)
|
|
108
|
+
# Returns: paged result set containing the resulting MyOrgUnitInfo data blocks
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Retrieve the enrolled users in the classlist for an org unit
|
|
112
|
+
def get_enrolled_users_in_classlist(org_unit_id)
|
|
113
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/classlist/"
|
|
114
|
+
_get(path)
|
|
115
|
+
# Returns: JSON array of ClasslistUser data blocks.
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Delete a user’s enrollment in a provided org unit.
|
|
119
|
+
def delete_user_enrollment(user_id, org_unit_id)
|
|
120
|
+
path = "/d2l/api/lp/#{$lp_ver}/users/#{user_id}/orgUnits/#{org_unit_id}"
|
|
121
|
+
_delete(path)
|
|
122
|
+
# Returns: EnrollmentData JSON block showing the enrollment status
|
|
123
|
+
# just before this action deleted the enrollment of the user
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# Delete a user’s enrollment in a provided org unit.
|
|
128
|
+
def delete_user_enrollment_alternative(user_id, org_unit_id)
|
|
129
|
+
path = "/d2l/api/lp/#{$lp_ver}/enrollments/orgUnits/#{org_unit_id}/users/#{user_id}"
|
|
130
|
+
_delete(path)
|
|
131
|
+
# Returns: EnrollmentData JSON block showing the enrollment status
|
|
132
|
+
# just before this action deleted the enrollment of the user
|
|
133
|
+
end
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
require_relative 'requests'
|
|
2
|
+
require 'json-schema'
|
|
3
|
+
####################################
|
|
4
|
+
# Groups/Group Categories:##########
|
|
5
|
+
####################################
|
|
6
|
+
# Delete a particular group category from an org unit.
|
|
7
|
+
def delete_group_category(org_unit_id, group_category_id)
|
|
8
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}"
|
|
9
|
+
_delete(path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Delete a particular group from an org unit.
|
|
13
|
+
def delete_group(org_unit_id, group_category_id, group_id)
|
|
14
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/(groupId)"
|
|
15
|
+
_delete(path)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Remove a particular user from a group.
|
|
19
|
+
def remove_user_from_group(org_unit_id, group_category_id, group_id, user_id)
|
|
20
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/#{group_id}/enrollments/#{user_id}"
|
|
21
|
+
_delete(path)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Retrieve a list of all the group categories for the provided org unit.
|
|
25
|
+
def get_all_org_unit_group_categories(org_unit_id)
|
|
26
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/"
|
|
27
|
+
_get(path)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Retrieve a particular group category for an org unit.
|
|
31
|
+
def get_org_unit_group_category(org_unit_id, group_category_id)
|
|
32
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}"
|
|
33
|
+
_get(path)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Retrieve a list of all the groups in a specific group category for an OrgUnit
|
|
37
|
+
def get_all_group_category_groups(org_unit_id, group_category_id)
|
|
38
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/"
|
|
39
|
+
_get(path)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Retrieve a particular group in an org unit.
|
|
43
|
+
def get_org_unit_group(org_unit_id, group_category_id, group_id)
|
|
44
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/#{group_id}"
|
|
45
|
+
_get(path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
######
|
|
49
|
+
######
|
|
50
|
+
|
|
51
|
+
def validate_create_group_category_data(group_category_data)
|
|
52
|
+
schema = {
|
|
53
|
+
'type' => 'object',
|
|
54
|
+
'required' => %w(Name Description EnrollmentStyle
|
|
55
|
+
EnrollmentQuality AutoEnroll RandomizeEnrollments
|
|
56
|
+
NumberOfGroups MaxUsersPerGroup AllocateAfterExpiry
|
|
57
|
+
SelfEnrollmentExpiryDate GroupPrefix),
|
|
58
|
+
'properties' => {
|
|
59
|
+
'Name' => { 'type' => 'string' },
|
|
60
|
+
'Description' =>
|
|
61
|
+
{
|
|
62
|
+
'type' => 'object',
|
|
63
|
+
'properties'=>{
|
|
64
|
+
"Content" => "string",
|
|
65
|
+
"Type" => "string" #"Text|HTML"
|
|
66
|
+
}
|
|
67
|
+
}, #RichTextInput
|
|
68
|
+
# if set to SingleUserMemberSpecificGroup, values set for NumberOfGroups
|
|
69
|
+
# and MaxUsersPerGroup are IGNORED
|
|
70
|
+
# ----------------------------------
|
|
71
|
+
# GPRENROLL_T integer value meanings
|
|
72
|
+
# 0 = NumberOfGrupsNoEnrollment ^
|
|
73
|
+
# 1 = PeoplePerGroupAutoEnrollment
|
|
74
|
+
# 2 = NumerOfGroupsAutoEnrollment
|
|
75
|
+
# 3 = PeoplePerGroupSelfEnrollment
|
|
76
|
+
# 4 = SelfEnrollmentNumberOfGroups
|
|
77
|
+
# 5 = PeoplePerNumberOfGroupsSelfEnrollment
|
|
78
|
+
# ----------------------------------
|
|
79
|
+
'EnrollmentStyle' => { 'type' => 'integer' }, #num GRPENROLL_T
|
|
80
|
+
# if non-nil, values for NumberOfGroups and MaxUsersPerGroup are IGNORED
|
|
81
|
+
'EnrollmentQuantity' => { 'type' => %w(integer null) },
|
|
82
|
+
'AutoEnroll' => { 'type' => 'boolean'},
|
|
83
|
+
'RandomizeEnrollments' => { 'type' => 'boolean' },
|
|
84
|
+
'NumberOfGroups' => { 'type' => %w(integer null) }, #nil, 0, 1, 3, 5
|
|
85
|
+
'MaxUsersPerGroup' => { 'type' => %w(integer null) }, #1, 3, 5
|
|
86
|
+
# if MaxUsersPerGroup has a value, then set this to true.
|
|
87
|
+
'AllocateAfterExpiry' => { 'type' => 'boolean' },
|
|
88
|
+
'SelfEnrollmentExpiryDate' => { 'type' => %w(string null) }, #UTCDATETIME
|
|
89
|
+
# Prepends group prefix to GroupName and GroupCode
|
|
90
|
+
'GroupPrefix' => { 'type' => %w(string null) }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
JSON::Validator.validate!(schema, group_category_data, validate_schema: true)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
####
|
|
97
|
+
#### See +validate_create_group_category_data+ for details on schema formal
|
|
98
|
+
#### requirements of values
|
|
99
|
+
# Create a new group category for an org unit.
|
|
100
|
+
def create_org_unit_group_category(org_unit_id, group_category_data)
|
|
101
|
+
payload = { 'Name' => '', # String
|
|
102
|
+
'Description' => {}, # RichTextInput
|
|
103
|
+
'EnrollmentStyle' => 0, # number : group_enroll
|
|
104
|
+
'EnrollmentQuantity' => nil, # number | null
|
|
105
|
+
'AutoEnroll' => false, # bool
|
|
106
|
+
'RandomizeEnrollments' => false, # bool
|
|
107
|
+
'NumberOfGroups' => nil, # number | nil
|
|
108
|
+
'MaxUsersPerGroup' => nil, # number | nil
|
|
109
|
+
'AllocateAfterExpiry' => false, # bool
|
|
110
|
+
'SelfEnrollmentExpiryDate' => nil, # string: UTCDateTime | nil
|
|
111
|
+
'GroupPrefix' => nil, # String | nil
|
|
112
|
+
}.merge!(group_category_data)
|
|
113
|
+
# Requires: JSON block of GroupCategoryData
|
|
114
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/"
|
|
115
|
+
_post(path, payload)
|
|
116
|
+
# returns a GroupCategoryData JSON block, in the Fetch form, of the new categ.
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def validate_group_data(group_data)
|
|
120
|
+
schema =
|
|
121
|
+
{
|
|
122
|
+
'type' => 'object',
|
|
123
|
+
'required' => %w(Name Code Description),
|
|
124
|
+
'properties' =>
|
|
125
|
+
{
|
|
126
|
+
'Name' => { 'type' => 'string' },
|
|
127
|
+
"Code" => {'type' => 'string'},
|
|
128
|
+
'Description' =>
|
|
129
|
+
{
|
|
130
|
+
'type' => 'object',
|
|
131
|
+
'properties'=>
|
|
132
|
+
{
|
|
133
|
+
"Content" => "string",
|
|
134
|
+
"Type" => "string" #"Text|HTML"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
JSON::Validator.validate!(schema, group_data, validate_schema: true)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Create a new group for an org unit.
|
|
143
|
+
def create_org_unit_group(org_unit_id, group_category_id, group_data)
|
|
144
|
+
payload =
|
|
145
|
+
{
|
|
146
|
+
"Name" => "string",
|
|
147
|
+
"Code" => "string",
|
|
148
|
+
"Description" => {}
|
|
149
|
+
}.merge!(group_data)
|
|
150
|
+
# Requires: JSON block of GroupData
|
|
151
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/"
|
|
152
|
+
_post(path, payload)
|
|
153
|
+
# returns a GroupData JSON block, in the Fetch form, of the new group
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Update a particular group for an org unit
|
|
157
|
+
def update_org_unit_group(org_unit_id, group_category_id, group_id, group_data)
|
|
158
|
+
payload = {
|
|
159
|
+
"Name" => "string",
|
|
160
|
+
"Code" => "string",
|
|
161
|
+
"Description" => {}
|
|
162
|
+
}.merge!(group_data)
|
|
163
|
+
# Requires: JSON block of GroupData
|
|
164
|
+
validate_group_data(payload)
|
|
165
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/#{group_id}"
|
|
166
|
+
# returns a GroupData JSON block, in the Fetch form, of the updated group.
|
|
167
|
+
_put(path, payload)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def validate_group_enrollment_data(group_enrollment_data)
|
|
171
|
+
schema = {
|
|
172
|
+
'type' => 'object',
|
|
173
|
+
'required' => %w(UserId),
|
|
174
|
+
'properties' => {
|
|
175
|
+
'UserId' => { 'type' => 'integer' }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
JSON::Validator.validate!(schema, course_data, validate_schema: true)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Enroll a user in a group
|
|
182
|
+
def enroll_user_in_group(org_unit_id, group_category_id, group_id, user_id)
|
|
183
|
+
payload = {
|
|
184
|
+
"UserId" => user_id
|
|
185
|
+
}
|
|
186
|
+
# Requires: JSON block of GroupEnrollment
|
|
187
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/groups/#{group_id}/enrollments/"
|
|
188
|
+
validate_group_enrollment_data(payload)
|
|
189
|
+
_post(path, payload)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def validate_update_group_category_data(group_category_data)
|
|
193
|
+
schema = {
|
|
194
|
+
'type' => 'object',
|
|
195
|
+
'required' => %w(Name Description AutoEnroll RandomizeEnrollments),
|
|
196
|
+
'properties' => {
|
|
197
|
+
'Name' => { 'type' => 'string' },
|
|
198
|
+
'Description' =>
|
|
199
|
+
{
|
|
200
|
+
'type' => 'object',
|
|
201
|
+
'properties'=>{
|
|
202
|
+
"Content" => "string",
|
|
203
|
+
"Type" => "string" #"Text|HTML"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
'AutoEnroll' => { 'type' => 'boolean'},
|
|
207
|
+
'RandomizeEnrollments' => { 'type' => 'boolean' }
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
JSON::Validator.validate!(schema, group_category_data, validate_schema: true)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# update a particular group category for an org unit
|
|
214
|
+
def update_org_unit_group_category(org_unit_id, group_category_id, group_category_data)
|
|
215
|
+
|
|
216
|
+
payload = { 'Name' => '', # String
|
|
217
|
+
'Description' => {}, # RichTextInput
|
|
218
|
+
'AutoEnroll' => false, # bool
|
|
219
|
+
'RandomizeEnrollments' => false, # bool
|
|
220
|
+
}.merge!(group_category_data)
|
|
221
|
+
# Requires: JSON block of GroupCategoryData
|
|
222
|
+
validate_update_group_category_data(payload)
|
|
223
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_data}"
|
|
224
|
+
_put(path, payload)
|
|
225
|
+
# Returns a GroupCategoryData JSON block, in the Fetch form, of updated grp. cat.
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def is_group_category_locker_set_up(org_unit_id, group_category_id)
|
|
229
|
+
path = "/d2l/api/lp/#{$lp_ver}/#{org_unit_id}/groupcategories/#{group_category_id}/locker"
|
|
230
|
+
_get(path)["HasLocker"]
|
|
231
|
+
#returns true if the group cat. locker has been setup already
|
|
232
|
+
end
|