canvas_shim 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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