canvas_shim 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +21 -0
  5. data/app/assets/config/canvas_shim_manifest.js +2 -0
  6. data/app/assets/javascripts/canvas_shim/application.js +13 -0
  7. data/app/assets/stylesheets/canvas_shim/application.css +15 -0
  8. data/app/controllers/canvas_shim/application_controller.rb +12 -0
  9. data/app/controllers/canvas_shim/settings_api/swagger_controller.rb +11 -0
  10. data/app/controllers/canvas_shim/settings_api/v1/users_controller.rb +27 -0
  11. data/app/deploy/canvas_shim_asset_uploader.rb +19 -0
  12. data/app/helpers/canvas_shim/application_helper.rb +4 -0
  13. data/app/jobs/canvas_shim/application_job.rb +4 -0
  14. data/app/mailers/canvas_shim/application_mailer.rb +6 -0
  15. data/app/models/canvas_shim/application_record.rb +5 -0
  16. data/app/services/courses_service.rb +5 -0
  17. data/app/services/courses_service/commands/distribute_due_dates.rb +50 -0
  18. data/app/services/courses_service/commands/distribute_due_dates/scheduler.rb +70 -0
  19. data/app/services/grades_service.rb +33 -0
  20. data/app/services/grades_service/account.rb +13 -0
  21. data/app/services/grades_service/commands/zero_out_assignment_grades.rb +73 -0
  22. data/app/services/grades_service/commands/zero_out_assignment_grades_rollback.rb +38 -0
  23. data/app/services/pipeline_service.rb +27 -0
  24. data/app/services/pipeline_service/account.rb +9 -0
  25. data/app/services/pipeline_service/api/publish.rb +53 -0
  26. data/app/services/pipeline_service/commands/publish.rb +44 -0
  27. data/app/services/pipeline_service/commands/publish_events.rb +17 -0
  28. data/app/services/pipeline_service/endpoints/pipeline.rb +62 -0
  29. data/app/services/pipeline_service/endpoints/pipeline/message_builder.rb +75 -0
  30. data/app/services/pipeline_service/events/emitter.rb +56 -0
  31. data/app/services/pipeline_service/events/graded_out_event.rb +31 -0
  32. data/app/services/pipeline_service/events/http_client.rb +14 -0
  33. data/app/services/pipeline_service/events/responders/sis.rb +66 -0
  34. data/app/services/pipeline_service/events/subscription.rb +11 -0
  35. data/app/services/pipeline_service/http_client.rb +21 -0
  36. data/app/services/pipeline_service/logger.rb +39 -0
  37. data/app/services/pipeline_service/pipeline_client.rb +41 -0
  38. data/app/services/pipeline_service/serializers/assignment.rb +55 -0
  39. data/app/services/pipeline_service/serializers/base_methods.rb +33 -0
  40. data/app/services/pipeline_service/serializers/canvas_api_enrollment.rb +55 -0
  41. data/app/services/pipeline_service/serializers/enrollment.rb +31 -0
  42. data/app/services/pipeline_service/serializers/fetcher.rb +17 -0
  43. data/app/services/pipeline_service/serializers/submission.rb +30 -0
  44. data/app/services/pipeline_service/serializers/user.rb +31 -0
  45. data/app/services/settings_service.rb +51 -0
  46. data/app/services/settings_service/api_docs.yml +68 -0
  47. data/app/services/settings_service/assignment.rb +24 -0
  48. data/app/services/settings_service/assignment_repository.rb +89 -0
  49. data/app/services/settings_service/auth_middleware.rb +19 -0
  50. data/app/services/settings_service/auth_token.rb +21 -0
  51. data/app/services/settings_service/authenticator_stub.rb +9 -0
  52. data/app/services/settings_service/commands/get_enrollment_settings.rb +17 -0
  53. data/app/services/settings_service/commands/get_settings.rb +34 -0
  54. data/app/services/settings_service/commands/get_user_settings.rb +18 -0
  55. data/app/services/settings_service/commands/update_enrollment_setting.rb +22 -0
  56. data/app/services/settings_service/commands/update_settings.rb +38 -0
  57. data/app/services/settings_service/commands/update_user_setting.rb +21 -0
  58. data/app/services/settings_service/enrollment.rb +28 -0
  59. data/app/services/settings_service/queries/zero_grader_audit.rb +6 -0
  60. data/app/services/settings_service/repository.rb +93 -0
  61. data/app/services/settings_service/school.rb +26 -0
  62. data/app/services/settings_service/student_assignment.rb +24 -0
  63. data/app/services/settings_service/student_assignment_repository.rb +116 -0
  64. data/app/services/settings_service/submission.rb +24 -0
  65. data/app/services/settings_service/user.rb +28 -0
  66. data/app/views/layouts/canvas_shim/application.html.erb +14 -0
  67. data/config/initializers/hash.rb +17 -0
  68. data/config/initializers/string.rb +9 -0
  69. data/config/routes.rb +9 -0
  70. data/lib/canvas_shim.rb +5 -0
  71. data/lib/canvas_shim/engine.rb +12 -0
  72. data/lib/canvas_shim/version.rb +3 -0
  73. data/lib/tasks/canvas_shim_tasks.rake +7 -0
  74. metadata +214 -0
@@ -0,0 +1,24 @@
1
+ module SettingsService
2
+ class Assignment
3
+ def self.table_name
4
+ [SettingsService.canvas_domain, '-', 'assignment_settings'].join('')
5
+ end
6
+ def self.put(id:, setting: , value:)
7
+ AssignmentRepository.put(
8
+ table_name: table_name,
9
+ id: id,
10
+ setting: setting,
11
+ value: value
12
+ )
13
+ end
14
+ def table_name
15
+ self.class.table_name
16
+ end
17
+ def self.create_table
18
+ AssignmentRepository.create_table(name: table_name)
19
+ end
20
+ def self.get(id:)
21
+ AssignmentRepository.get(table_name: table_name, id: id)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ require 'forwardable'
2
+ module SettingsService
3
+ class AssignmentRepository
4
+ include Singleton
5
+
6
+ class << self
7
+ extend Forwardable
8
+ def_delegators :instance, :create_table, :get, :put
9
+ end
10
+
11
+ def initialize
12
+ raise "missing canvas domain!" if SettingsService.canvas_domain.nil?
13
+ @secret_key = ENV['S3_ACCESS_KEY']
14
+ @id_key = ENV['S3_ACCESS_KEY_ID']
15
+ Aws.config.update(
16
+ region: 'us-west-2',
17
+ credentials: creds
18
+ )
19
+ end
20
+
21
+ def create_table(name:)
22
+ begin
23
+ dynamodb.create_table(table_params(name)).successful?
24
+ rescue
25
+ end
26
+ end
27
+
28
+ def get(table_name:, id:)
29
+ dynamodb.query(
30
+ table_name: table_name,
31
+ key_condition_expression: "#id = :id",
32
+ expression_attribute_names: { "#id" => "id" },
33
+ expression_attribute_values: { ":id" => id }
34
+ ).items.inject({}) do |newhash, setting|
35
+ newhash[setting['setting']] = setting['value']
36
+ newhash
37
+ end
38
+ end
39
+
40
+ def put(table_name:, id:, setting:, value:)
41
+ dynamodb.put_item(
42
+ table_name: table_name,
43
+ item: {
44
+ id: id,
45
+ setting: setting,
46
+ value: value
47
+ }
48
+ )
49
+ end
50
+
51
+ def self.use_test_client!
52
+ instance.use_test_client!
53
+ end
54
+
55
+ def use_test_client!
56
+ Aws.config = {}
57
+ @dynamodb = Aws::DynamoDB::Client.new(endpoint: 'http://localhost:8000')
58
+ end
59
+
60
+ private
61
+
62
+ def dynamodb
63
+ @dynamodb || Aws::DynamoDB::Client.new
64
+ end
65
+
66
+ def creds
67
+ Aws::Credentials.new(@id_key, @secret_key)
68
+ end
69
+
70
+ def table_params(name)
71
+ {
72
+ table_name: name,
73
+ key_schema: [
74
+ { attribute_name: 'id', key_type: 'HASH' },
75
+ { attribute_name: 'setting', key_type: 'RANGE'},
76
+ ],
77
+ attribute_definitions: [
78
+ { attribute_name: 'id', attribute_type: 'S' },
79
+ { attribute_name: 'setting', attribute_type: 'S' },
80
+ ],
81
+ provisioned_throughput: {
82
+ read_capacity_units: 10,
83
+ write_capacity_units: 10
84
+ }
85
+ }
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,19 @@
1
+ module SettingsService
2
+ class AuthMiddleware
3
+ def initialize app, arg2
4
+ @arg2 = arg2
5
+ @app = app
6
+ end
7
+
8
+ def call env
9
+ key = env['HTTP_AUTHORIZATION']
10
+ key = key.delete('Bearer ') if key
11
+
12
+ if AuthToken.authenticate(key)
13
+ @app.call(env)
14
+ else
15
+ [401, {"Content-Type" => "application/json"}, ['{ "message" : "Unauthorized" }']]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module SettingsService
2
+ class AuthToken
3
+ cattr_writer :authenticator
4
+
5
+ # Set SettingsService::AuthToken.authenticator to override
6
+ # in the LMS
7
+ def self.authenticator
8
+ @@authenticator || AuthenticatorStub
9
+ end
10
+
11
+ def self.authenticate(key)
12
+ return valid_token?(authenticator.authenticate(key))
13
+ end
14
+
15
+ def self.valid_token?(token)
16
+ return false if token.nil?
17
+ token.user.user_roles(Account.site_admin).include?('root_admin')
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ # This won't be used in production. Set AuthToken.authenticator = ::AccessToken
2
+ # a CanvasLMS initializer
3
+ module SettingsService
4
+ class AuthenticatorStub
5
+ def self.authenticate(key)
6
+ true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module SettingsService
2
+ module Commands
3
+ class GetEnrollmentSettings
4
+ def initialize id:
5
+ @id = id
6
+ end
7
+
8
+ # DEPRICATED: Use "GetSettings instead"
9
+ def call
10
+ SettingsService::Enrollment.create_table
11
+ SettingsService::Enrollment.get(
12
+ id: @id
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ module SettingsService
2
+ module Commands
3
+ class GetSettings
4
+ def initialize(id:, object:)
5
+ @id = id
6
+ @object = object
7
+ end
8
+
9
+ def call
10
+ object.create_table
11
+ object.get(id: @id)
12
+ end
13
+
14
+ private
15
+
16
+ def object
17
+ case @object.to_s
18
+ when 'assignment'
19
+ SettingsService::Assignment
20
+ when 'user'
21
+ SettingsService::User
22
+ when 'enrollment'
23
+ SettingsService::Enrollment
24
+ when 'student_assignment'
25
+ SettingsService::StudentAssignment
26
+ when 'school'
27
+ SettingsService::School
28
+ else
29
+ raise "Unrecognized Object: #{@object}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module SettingsService
3
+ module Commands
4
+ # DEPRICATED: Use "GetSettings instead"
5
+ class GetUserSettings
6
+ def initialize id:
7
+ @id = id
8
+ end
9
+
10
+ def call
11
+ SettingsService::User.create_table
12
+ SettingsService::User.get(
13
+ id: @id
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module SettingsService
2
+ module Commands
3
+ # DEPRICATED: Use "UpdateSettings instead"
4
+ class UpdateEnrollmentSetting
5
+ def initialize id:, setting:, value:
6
+ @id = id
7
+ @setting = setting
8
+ @value = value
9
+ end
10
+
11
+
12
+ def call
13
+ SettingsService::Enrollment.create_table
14
+ SettingsService::Enrollment.put(
15
+ id: @id,
16
+ setting: @setting,
17
+ value: @value
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ module SettingsService
2
+ module Commands
3
+ class UpdateSettings
4
+ def initialize id:, setting:, value:, object:
5
+ @id = id
6
+ @setting = setting
7
+ @value = value
8
+ @object = object
9
+ end
10
+
11
+ def call
12
+ object.create_table
13
+ object.put(id: @id, setting: @setting, value: @value)
14
+ end
15
+
16
+ private
17
+
18
+ def object
19
+ case @object
20
+ when 'assignment'
21
+ SettingsService::Assignment
22
+ when 'user'
23
+ SettingsService::User
24
+ when 'enrollment'
25
+ SettingsService::Enrollment
26
+ when 'student_assignment'
27
+ SettingsService::StudentAssignment
28
+ when 'school'
29
+ SettingsService::School
30
+ when 'submission'
31
+ SettingsService::Submission
32
+ else
33
+ raise "Unrecognized Object: #{@object}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module SettingsService
2
+ module Commands
3
+ class UpdateUserSetting
4
+ # DEPRICATED: Use "UpdateSettings instead"
5
+ def initialize id:, setting:, value:
6
+ @id = id
7
+ @setting = setting
8
+ @value = value
9
+ end
10
+
11
+ def call
12
+ SettingsService::User.create_table
13
+ SettingsService::User.put(
14
+ id: @id,
15
+ setting: @setting,
16
+ value: @value
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module SettingsService
2
+ class Enrollment
3
+ def self.create_table
4
+ Repository.create_table(name: table_name)
5
+ end
6
+
7
+ def self.put(id:, setting: , value:)
8
+ Repository.put(
9
+ table_name: table_name,
10
+ id: id,
11
+ setting: setting,
12
+ value: value
13
+ )
14
+ end
15
+
16
+ def self.get(id:)
17
+ Repository.get(table_name: table_name, id: id)
18
+ end
19
+
20
+ def self.table_name
21
+ [SettingsService.canvas_domain, '-', 'enrollment_settings'].join('')
22
+ end
23
+
24
+ def table_name
25
+ self.class.table_name
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module SettingsService
2
+ module Queries
3
+ class ZeroGraderAudit
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,93 @@
1
+ require 'forwardable'
2
+ module SettingsService
3
+ class Repository
4
+ include Singleton
5
+
6
+ class << self
7
+ extend Forwardable
8
+ def_delegators :instance, :create_table, :get, :put
9
+ end
10
+
11
+ def initialize
12
+ raise "missing canvas domain!" if SettingsService.canvas_domain.nil?
13
+ @secret_key = ENV['S3_ACCESS_KEY']
14
+ @id_key = ENV['S3_ACCESS_KEY_ID']
15
+ Aws.config.update(
16
+ region: 'us-west-2',
17
+ credentials: creds
18
+ )
19
+ end
20
+
21
+ def create_table(name:)
22
+ begin
23
+ dynamodb.create_table(table_params(name)).successful?
24
+ rescue
25
+ end
26
+ end
27
+
28
+ def get(table_name:, id:)
29
+ begin
30
+ dynamodb.query(
31
+ table_name: table_name,
32
+ key_condition_expression: "#id = :id",
33
+ expression_attribute_names: { "#id" => "id" },
34
+ expression_attribute_values: { ":id" => id.to_i }
35
+ ).items.inject({}) do |newhash, setting|
36
+ newhash[setting['setting']] = setting['value']
37
+ newhash
38
+ end
39
+ rescue Aws::DynamoDB::Errors::ResourceNotFoundException
40
+ nil
41
+ end
42
+ end
43
+
44
+ def put(table_name:, id:, setting:, value:)
45
+ dynamodb.put_item(
46
+ table_name: table_name,
47
+ item: {
48
+ id: id.to_i,
49
+ setting: setting,
50
+ value: value
51
+ }
52
+ )
53
+ end
54
+
55
+ def self.use_test_client!
56
+ instance.use_test_client!
57
+ end
58
+
59
+ def use_test_client!
60
+ Aws.config = {}
61
+ @dynamodb = Aws::DynamoDB::Client.new(endpoint: 'http://localhost:8000')
62
+ end
63
+
64
+ private
65
+
66
+ def dynamodb
67
+ @dynamodb || Aws::DynamoDB::Client.new
68
+ end
69
+
70
+ def creds
71
+ Aws::Credentials.new(@id_key, @secret_key)
72
+ end
73
+
74
+ def table_params(name)
75
+ {
76
+ table_name: name,
77
+ key_schema: [
78
+ { attribute_name: 'id', key_type: 'HASH' },
79
+ { attribute_name: 'setting', key_type: 'RANGE'},
80
+ ],
81
+ attribute_definitions: [
82
+ { attribute_name: 'id', attribute_type: 'N' },
83
+ { attribute_name: 'setting', attribute_type: 'S' },
84
+ ],
85
+ provisioned_throughput: {
86
+ read_capacity_units: 10,
87
+ write_capacity_units: 10
88
+ }
89
+ }
90
+ end
91
+
92
+ end
93
+ end