japanda 0.1.0 → 0.1.5
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 +5 -5
- data/.env.example +4 -0
- data/.gitignore +2 -2
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Dockerfile +9 -0
- data/Gemfile.lock +62 -0
- data/Jenkinsfile +64 -0
- data/README.md +57 -15
- data/docker-compose.yml +11 -0
- data/japanda.gemspec +19 -19
- data/lib/japanda.rb +3 -11
- data/lib/japanda/canvas_factory.rb +24 -0
- data/lib/japanda/canvas_factory/assignment.rb +38 -0
- data/lib/japanda/canvas_factory/course.rb +82 -0
- data/lib/japanda/canvas_factory/mergie.rb +10 -0
- data/lib/japanda/canvas_factory/module.rb +51 -0
- data/lib/japanda/canvas_factory/module_item.rb +37 -0
- data/lib/japanda/canvas_factory/quiz.rb +52 -0
- data/lib/japanda/canvas_factory/section.rb +36 -0
- data/lib/japanda/canvas_factory/user.rb +67 -0
- data/lib/japanda/version.rb +1 -1
- metadata +72 -38
- data/LICENSE.txt +0 -21
- data/lib/canvas_factory/assignment.rb +0 -31
- data/lib/canvas_factory/course.rb +0 -55
- data/lib/canvas_factory/module.rb +0 -46
- data/lib/canvas_factory/module_item.rb +0 -31
- data/lib/canvas_factory/section.rb +0 -22
- data/lib/canvas_factory/user.rb +0 -28
- data/lib/canvas_factory/user_config.rb +0 -41
- data/lib/catalog_factory/course_program.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6d62c0b18d1c9844e0c9a62343edc2d681412c3bb453a7028d1c33ae47bfddac
|
4
|
+
data.tar.gz: 34bcfd1ac14c12c5fe61889bfd2c567edf6fcbf816fe5bce6f7d025154ced604
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38640dbdb09ffcf289130b8791ee5a6be3be255aa41b15359b4398efee7e51134e2879fecffda211aba59eacb1eccc56622fdae264d320b5036b9a0a9ccb1022
|
7
|
+
data.tar.gz: 70e93dbb2e8563b1724c36d9a9fc4eaef3f263a3c3ddfaae6c3ecefc09a253cb427f8c802e791f3a85987320eb4c53463f0594b4be2a4506525e1376909915b0
|
data/.env.example
ADDED
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.0
|
data/Dockerfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
japanda (0.1.5)
|
5
|
+
rest-client (>= 2.1.0)
|
6
|
+
rspec_junit_formatter (~> 0.4.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
byebug (11.1.3)
|
12
|
+
diff-lcs (1.4.4)
|
13
|
+
domain_name (0.5.20190701)
|
14
|
+
unf (>= 0.0.5, < 1.0.0)
|
15
|
+
dotenv (2.0.2)
|
16
|
+
hashie (4.0.0)
|
17
|
+
http-accept (1.7.0)
|
18
|
+
http-cookie (1.0.3)
|
19
|
+
domain_name (~> 0.5)
|
20
|
+
mime-types (3.3.1)
|
21
|
+
mime-types-data (~> 3.2015)
|
22
|
+
mime-types-data (3.2020.1104)
|
23
|
+
netrc (0.11.0)
|
24
|
+
rake (10.4.2)
|
25
|
+
rest-client (2.1.0)
|
26
|
+
http-accept (>= 1.7.0, < 2.0)
|
27
|
+
http-cookie (>= 1.0.2, < 2.0)
|
28
|
+
mime-types (>= 1.16, < 4.0)
|
29
|
+
netrc (~> 0.8)
|
30
|
+
rspec (3.5.0)
|
31
|
+
rspec-core (~> 3.5.0)
|
32
|
+
rspec-expectations (~> 3.5.0)
|
33
|
+
rspec-mocks (~> 3.5.0)
|
34
|
+
rspec-core (3.5.4)
|
35
|
+
rspec-support (~> 3.5.0)
|
36
|
+
rspec-expectations (3.5.0)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.5.0)
|
39
|
+
rspec-mocks (3.5.0)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.5.0)
|
42
|
+
rspec-support (3.5.0)
|
43
|
+
rspec_junit_formatter (0.4.1)
|
44
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
45
|
+
unf (0.1.4)
|
46
|
+
unf_ext
|
47
|
+
unf_ext (0.0.7.7)
|
48
|
+
|
49
|
+
PLATFORMS
|
50
|
+
ruby
|
51
|
+
|
52
|
+
DEPENDENCIES
|
53
|
+
bundler (~> 1.5)
|
54
|
+
byebug
|
55
|
+
dotenv
|
56
|
+
hashie (~> 4.0.0)
|
57
|
+
japanda!
|
58
|
+
rake
|
59
|
+
rspec (~> 3.5.0)
|
60
|
+
|
61
|
+
BUNDLED WITH
|
62
|
+
1.17.3
|
data/Jenkinsfile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#! /usr/bin/env groovy
|
2
|
+
|
3
|
+
String rspec_results = ''
|
4
|
+
String container_id = ''
|
5
|
+
|
6
|
+
pipeline {
|
7
|
+
agent { label 'docker' }
|
8
|
+
|
9
|
+
environment {
|
10
|
+
COMPOSE_PROJECT_NAME = 'japanda_build'
|
11
|
+
COMPOSE_FILE = 'docker-compose.yml'
|
12
|
+
}
|
13
|
+
|
14
|
+
options {
|
15
|
+
ansiColor("xterm")
|
16
|
+
}
|
17
|
+
|
18
|
+
stages {
|
19
|
+
stage('Build') {
|
20
|
+
steps {
|
21
|
+
echo 'Building the containers'
|
22
|
+
sh "docker-compose build --pull"
|
23
|
+
|
24
|
+
echo 'Starting containers'
|
25
|
+
sh "docker-compose up -d"
|
26
|
+
sh 'docker-compose run --no-deps -d testrunner tail -f /dev/null'
|
27
|
+
|
28
|
+
script {
|
29
|
+
sh "docker ps"
|
30
|
+
container_id = sh(script: "docker ps -qf 'name=testrunner'",
|
31
|
+
returnStdout: true
|
32
|
+
).trim()
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
}
|
37
|
+
|
38
|
+
stage('Run Rspec Tests') {
|
39
|
+
steps {
|
40
|
+
sh "docker exec $container_id bundle exec rspec spec/ >> rspec_results"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
post {
|
46
|
+
always {
|
47
|
+
script {
|
48
|
+
rspec_results = sh(script: 'cat rspec_results',
|
49
|
+
returnStdout: true
|
50
|
+
).trim()
|
51
|
+
|
52
|
+
sh "docker cp $container_id:/usr/src/app/junit ."
|
53
|
+
junit allowEmptyResults: true, testResults: 'junit/rspec.xml'
|
54
|
+
}
|
55
|
+
echo rspec_results
|
56
|
+
}
|
57
|
+
|
58
|
+
cleanup {
|
59
|
+
sh 'if [ -d "junit" ]; then rm -r "junit"; fi'
|
60
|
+
sh 'if [ -f "rspec_results" ]; then rm -rf "rspec_results"; fi'
|
61
|
+
sh "docker-compose down --remove-orphans --rmi=all --volumes"
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
data/README.md
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
# Japanda
|
2
2
|
|
3
|
-
|
3
|
+
Japanda provides an object-oriented and a functional wrapper around Instructure Canvas Api's
|
4
4
|
|
5
|
-
|
5
|
+
Disclaimer: For testing purposes only.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
|
-
|
12
|
-
gem 'japanda'
|
13
|
-
```
|
11
|
+
gem 'japanda'
|
14
12
|
|
15
13
|
And then execute:
|
16
14
|
|
@@ -21,26 +19,70 @@ Or install it yourself as:
|
|
21
19
|
$ gem install japanda
|
22
20
|
|
23
21
|
## Usage
|
24
|
-
Set a few enviroment variables:
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
export
|
29
|
-
export
|
30
|
-
export
|
23
|
+
Set a few enviroment variables( or use .env.example file)
|
24
|
+
|
25
|
+
export CANVAS_API_HOST=
|
26
|
+
export CANVAS_API_TOKEN=
|
27
|
+
export CANVAS_ACCOUNT_ID=
|
28
|
+
|
29
|
+
To create a new course
|
30
|
+
|
31
|
+
CanvasFactory::Course.new
|
32
|
+
|
33
|
+
To create a new course by providing a custom hash(merge)
|
34
|
+
|
35
|
+
opts = { course:{ name: 'coursename1', course_code: "code-change#{SecureRandom.hex}" } }
|
36
|
+
course = CanvasFactory::Course.new(opts)
|
37
|
+
|
38
|
+
To create a new course by providing a custom hash(no merge)
|
39
|
+
|
40
|
+
opts = {
|
41
|
+
account_id: '10',
|
42
|
+
course: {
|
43
|
+
name: "code-name#{SecureRandom.hex}",
|
44
|
+
course_code: "course_code#{SecureRandom.hex}"
|
45
|
+
},
|
46
|
+
offer: true
|
47
|
+
}
|
48
|
+
course = CanvasFactory::Course.new(opts, false)
|
31
49
|
|
32
50
|
## Development
|
33
51
|
|
34
|
-
After checking out the repo, run `
|
52
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rspec` to run the tests.
|
53
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
54
|
+
|
55
|
+
### Run in docker
|
56
|
+
|
57
|
+
Make sure your .env variable contains
|
58
|
+
```
|
59
|
+
CANVAS_API_HOST=<canvas_host>
|
60
|
+
CANVAS_API_TOKEN=<canvas_api_token>
|
61
|
+
CANVAS_ACCOUNT_ID=<canvas_account_id>
|
62
|
+
```
|
63
|
+
|
64
|
+
Building the testrunner
|
65
|
+
```
|
66
|
+
docker-compose build
|
67
|
+
```
|
68
|
+
|
69
|
+
Running the tests:
|
70
|
+
```
|
71
|
+
docker-compose run testrunner bundle exec rspec spec/
|
72
|
+
```
|
73
|
+
|
74
|
+
## Release a new version
|
75
|
+
|
76
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
35
77
|
|
36
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
37
78
|
|
38
79
|
## Contributing
|
39
80
|
|
40
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
81
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/babababili/japanda. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
41
82
|
|
42
83
|
|
43
84
|
## License
|
44
85
|
|
45
|
-
|
86
|
+
For testing purposes only.
|
46
87
|
|
88
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/docker-compose.yml
ADDED
data/japanda.gemspec
CHANGED
@@ -4,36 +4,36 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'japanda/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'japanda'
|
8
8
|
spec.version = Japanda::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ['Santosh Natarajan', 'Robert Lamb']
|
10
|
+
spec.email = ['snatarajan@instructure.com', 'rlamb@instructure.com']
|
11
11
|
|
12
|
-
spec.summary = %q{Library to create custom course
|
13
|
-
spec.description = %q{Library to create custom course
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
12
|
+
spec.summary = %q{Library to create custom course.}
|
13
|
+
spec.description = %q{Library to create custom course. wip.}
|
14
|
+
# spec.homepage = 'https://github.com/babababili/japanda'
|
15
|
+
# spec.license = 'MIT'
|
16
16
|
|
17
17
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
18
|
# delete this section to allow pushing this gem to any host.
|
19
19
|
# if spec.respond_to?(:metadata)
|
20
|
-
# spec.metadata['allowed_push_host'] =
|
20
|
+
# spec.metadata['allowed_push_host'] = 'TODO: Set to 'http://mygemserver.com''
|
21
21
|
# else
|
22
|
-
# raise
|
22
|
+
# raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
23
23
|
# end
|
24
24
|
|
25
25
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
-
spec.bindir =
|
26
|
+
spec.bindir = 'exe'
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
-
spec.require_paths = [
|
28
|
+
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency
|
32
|
-
spec.add_development_dependency
|
33
|
-
|
34
|
-
|
35
|
-
spec.
|
36
|
-
spec.add_dependency
|
37
|
-
spec.add_dependency
|
30
|
+
spec.add_development_dependency 'bundler', '~>1.5'
|
31
|
+
spec.add_development_dependency 'byebug'
|
32
|
+
spec.add_development_dependency 'dotenv'
|
33
|
+
spec.add_development_dependency 'hashie', '~>4.0.0'
|
34
|
+
spec.add_development_dependency 'rake'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.5.0'
|
36
|
+
spec.add_dependency 'rest-client', '>= 2.1.0'
|
37
|
+
spec.add_dependency 'rspec_junit_formatter', '~>0.4.1'
|
38
38
|
|
39
39
|
end
|
data/lib/japanda.rb
CHANGED
@@ -1,16 +1,8 @@
|
|
1
1
|
require 'japanda/version'
|
2
2
|
require 'securerandom'
|
3
|
-
require '
|
3
|
+
require 'rest-client'
|
4
|
+
require 'json'
|
5
|
+
require 'byebug'
|
4
6
|
|
5
7
|
module Japanda
|
6
|
-
Dotenv.load
|
7
|
-
CANVAS_USER_DOMAIN ||= ENV['CANVAS_USER_DOMAIN']
|
8
|
-
CANVAS_API_V1 ||= "#{ENV['CANVAS_API_HOST']}/api/v1"
|
9
|
-
CANVAS_AUTH_HEADER ||= {
|
10
|
-
Authorization: "Bearer #{ENV['CANVAS_API_TOKEN']}",
|
11
|
-
content_type: 'application/json'
|
12
|
-
}
|
13
|
-
CANVAS_ACCOUNT_ID ||= ENV['CANVAS_ACCOUNT_ID']
|
14
|
-
GALLERY_API_TOKEN ||= ENV['GALLERY_API_TOKEN']
|
15
|
-
GALLERY_API_HOST = ENV['GALLERY_API_HOST']
|
16
8
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'dotenv'
|
2
|
+
|
3
|
+
module CanvasFactory
|
4
|
+
Dotenv.load
|
5
|
+
CANVAS_API_V1 ||= "#{ENV['CANVAS_API_HOST']}/api/v1"
|
6
|
+
CANVAS_AUTH_HEADER ||= {
|
7
|
+
Authorization: "Bearer #{ENV['CANVAS_API_TOKEN']}",
|
8
|
+
content_type: 'application/json'
|
9
|
+
}
|
10
|
+
CANVAS_ACCOUNT_ID ||= ENV['CANVAS_ACCOUNT_ID']
|
11
|
+
|
12
|
+
# JSON.generate see: https://github.com/rest-client/rest-client/issues/635/
|
13
|
+
def self.perform_post(end_point, body)
|
14
|
+
JSON.parse(RestClient.post end_point, JSON.generate(body), CANVAS_AUTH_HEADER)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.perform_put(end_point, body)
|
18
|
+
JSON.parse(RestClient.put end_point, JSON.generate(body), CANVAS_AUTH_HEADER)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.perform_delete(end_point)
|
22
|
+
JSON.parse(RestClient.delete end_point, CANVAS_AUTH_HEADER)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module CanvasFactory
|
2
|
+
# assignment class
|
3
|
+
class Assignment
|
4
|
+
attr_reader :id, :name, :course_id, :html_url, :grading_type, :published, :due_at,
|
5
|
+
:created_at, :request, :response
|
6
|
+
|
7
|
+
def initialize(course_id, opts = {}, merge = true)
|
8
|
+
@course_id = course_id
|
9
|
+
@request = {
|
10
|
+
assignment: {
|
11
|
+
name: "Assignment-#{Time.now.to_i}",
|
12
|
+
grading_type: %w(pass_fail percent letter_grade gpa_scale points).sample,
|
13
|
+
submission_types: ['online_text_entry'],
|
14
|
+
points_possible: 10,
|
15
|
+
due_at: (DateTime.now + 1).iso8601,
|
16
|
+
published: true
|
17
|
+
}
|
18
|
+
}
|
19
|
+
@request = Mergie.deep_merge(@request, opts, merge)
|
20
|
+
create_assignment
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_assignment
|
27
|
+
assign_end_point = "#{CANVAS_API_V1}/courses/#{@course_id}/assignments"
|
28
|
+
@response = CanvasFactory.perform_post(assign_end_point, @request)
|
29
|
+
@id = response['id']
|
30
|
+
@name = response['name']
|
31
|
+
@html_url = response['html_url']
|
32
|
+
@grading_type = response['grading_type']
|
33
|
+
@published = response['published']
|
34
|
+
@created_at = response['created_at']
|
35
|
+
@due_at = response['due_at']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module CanvasFactory
|
2
|
+
# canvas course class
|
3
|
+
class Course
|
4
|
+
attr_reader :course_response, :course_id, :course_code, :course_name, :course_request,
|
5
|
+
:sections, :modules, :assignments, :quizzes
|
6
|
+
|
7
|
+
def initialize(opts = {}, merge = true)
|
8
|
+
@sections = []
|
9
|
+
@modules = []
|
10
|
+
@assignments = []
|
11
|
+
@quizzes = []
|
12
|
+
course_name_code = "auto#{SecureRandom.hex}"
|
13
|
+
@course_request = {
|
14
|
+
account_id: CANVAS_ACCOUNT_ID,
|
15
|
+
course: {
|
16
|
+
name: course_name_code,
|
17
|
+
course_code: course_name_code,
|
18
|
+
start_at: Time.now,
|
19
|
+
end_at: Time.now + (30 * 24 * 60 * 60),
|
20
|
+
license: 'public_domain',
|
21
|
+
is_public: true,
|
22
|
+
is_public_to_auth_users: false,
|
23
|
+
public_syllabus: false,
|
24
|
+
public_description: 'api created course',
|
25
|
+
allow_student_wiki_edits: true,
|
26
|
+
allow_wiki_comments: true,
|
27
|
+
allow_student_forum_attachments: true,
|
28
|
+
open_enrollment: true,
|
29
|
+
self_enrollment: false,
|
30
|
+
restrict_enrollments_to_course_dates: false,
|
31
|
+
term_id: nil,
|
32
|
+
# sis_course_id: '', # field is included only when user has permission to view SIS information
|
33
|
+
# integration_id: '', # field is included only when user has permission to view SIS information
|
34
|
+
hide_final_grades: true,
|
35
|
+
apply_assignment_group_weights: false,
|
36
|
+
syllabus_body: 'api syllabus',
|
37
|
+
grading_standard_id: nil,
|
38
|
+
course_format: 'online'
|
39
|
+
},
|
40
|
+
offer: true,
|
41
|
+
enroll_me: false,
|
42
|
+
enable_sis_reactivation: false
|
43
|
+
}
|
44
|
+
@course_request = Mergie.deep_merge(@course_request, opts, merge)
|
45
|
+
create_course
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_section(opts = {}, merge = true)
|
49
|
+
section = CanvasFactory::Section.new(@course_id, opts, merge)
|
50
|
+
@sections << section
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_module(opts = {}, merge = true)
|
54
|
+
mod = CanvasFactory::Module.new(@course_id, opts, merge)
|
55
|
+
@modules << mod
|
56
|
+
mod
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_assignment(opts = {}, merge = true)
|
60
|
+
assignment = CanvasFactory::Assignment.new(@course_id, opts, merge)
|
61
|
+
@assignments << assignment
|
62
|
+
assignment
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_quiz(opts = {}, merge = true)
|
66
|
+
quiz = CanvasFactory::Quiz.new(@course_id, opts, merge)
|
67
|
+
@quizzes << quiz
|
68
|
+
quiz
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def create_course
|
74
|
+
course_end_point = "#{CANVAS_API_V1}/accounts/#{@course_request[:account_id]}/courses"
|
75
|
+
@course_response = CanvasFactory.perform_post(course_end_point, @course_request)
|
76
|
+
@course_id = @course_response['id']
|
77
|
+
@course_name = @course_response['name']
|
78
|
+
@course_code = @course_response['course_code']
|
79
|
+
self
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|