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,11 @@
1
+ module PipelineService
2
+ module Events
3
+ class Subscription
4
+ attr_reader :responder, :event
5
+ def initialize(event:, responder: nil)
6
+ @responder = responder
7
+ @event = event
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module PipelineService
2
+ class HTTPClient
3
+ include Singleton
4
+
5
+ def self.post(args)
6
+ instance.post(args)
7
+ end
8
+
9
+ def self.get(endpoint, args={})
10
+ instance.get(endpoint, args)
11
+ end
12
+
13
+ def post(args)
14
+ PipelinePublisher::MessagesApi.new.messages_post(*args)
15
+ end
16
+
17
+ def get(endpoint, args)
18
+ HTTParty.get(endpoint, args)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module PipelineService
2
+ class Logger
3
+ HEADERS = {}
4
+ def initialize(message, args={})
5
+ @message = message
6
+ @args = args
7
+ configure_dependencies
8
+ end
9
+
10
+ def call
11
+ if PipelineService.perform_synchronously?
12
+ perform
13
+ else
14
+ queue.enqueue(self)
15
+ end
16
+ end
17
+
18
+ # This makes it possible for the instance to be run later by Delayed::Job
19
+ def perform
20
+ post
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :http_client, :message, :queue
26
+
27
+ def configure_dependencies
28
+ @queue = @args[:queue] || Delayed::Job
29
+ @http_client = @args[:http_client] || HTTParty
30
+ end
31
+
32
+ def post
33
+ http_client.post(
34
+ 'https://3wupzgqsoh.execute-api.us-west-2.amazonaws.com/prod',
35
+ body: message.to_json
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ module PipelineService
2
+ # PipelineClient builds a pipeline message using the object
3
+ # posts it to the endpoint and logs the message that was sent.
4
+ #
5
+ # Accepts an ActiveRecord object or a hash. If using a hash, you must provide
6
+ # a noun as an optional parameter
7
+ #
8
+ # PipelineCient.new(object: Enrollment.last)
9
+ # PipelineCient.new(object: { data: { foo: 'bar' } }, noun: 'enrollment' )
10
+ class PipelineClient
11
+ def initialize(args)
12
+ @args = args
13
+ @object = args[:object]
14
+ configure_dependencies
15
+ end
16
+
17
+ def call
18
+ fetch_enrollment_from_hash
19
+ post
20
+ self
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :endpoint, :object
26
+
27
+ def configure_dependencies
28
+ @endpoint = @args[:endpoint] || Endpoints::Pipeline
29
+ end
30
+
31
+ # EVIL! I'm rewriting an arg. What could go wrong?
32
+ def fetch_enrollment_from_hash
33
+ return unless object.is_a?(Hash)
34
+ @args[:object] = Enrollment.find(object[:id])
35
+ end
36
+
37
+ def post
38
+ endpoint.new(@args).call
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,55 @@
1
+ module PipelineService
2
+ module Serializers
3
+ class Assignment
4
+ def initialize(object:)
5
+ @object = object
6
+ end
7
+
8
+ def call
9
+ fetch
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :object
15
+
16
+ def domain
17
+ ENV['CANVAS_DOMAIN']
18
+ end
19
+
20
+ def endpoint
21
+ [
22
+ protocol, domain, ':', port,
23
+ '/api/v1/courses/', course_id, '/assignments/', object.id
24
+ ].join('')
25
+ end
26
+
27
+ def use_ssl?
28
+ ENV['CANVAS_SSL'] == 'true'
29
+ end
30
+
31
+ def port
32
+ return '3000' if Rails.env == 'development'
33
+ return '443' if use_ssl?
34
+ '80'
35
+ end
36
+
37
+ def headers
38
+ { Authorization: "Bearer #{ENV['STRONGMIND_INTEGRATION_KEY']}" }
39
+ end
40
+
41
+ def fetch
42
+ PipelineService::HTTPClient.get(endpoint, headers: headers).parsed_response
43
+ end
44
+
45
+ def course_id
46
+ object.course.id
47
+ end
48
+
49
+ def protocol
50
+ return 'https://' if use_ssl?
51
+ 'http://'
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ module PipelineService
2
+ module Serializers
3
+ module BaseMethods
4
+ private
5
+
6
+ def protocol
7
+ ENV['CANVAS_SSL'] == 'true' ? 'https://' : 'http://'
8
+ end
9
+
10
+ def host
11
+ ENV['CANVAS_DOMAIN']
12
+ end
13
+
14
+ def port
15
+ 80
16
+ end
17
+
18
+ def host_with_port
19
+ "#{host}:#{port}"
20
+ end
21
+
22
+ def ssl?
23
+ ENV['CANVAS_SSL'] == 'true'
24
+ end
25
+
26
+ def request
27
+ Struct.new(:host_with_port, :ssl?, :protocol, :host, :port).new(
28
+ host_with_port, ssl?, protocol, host, port
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,55 @@
1
+ module PipelineService
2
+ module Serializers
3
+ class CanvasAPIEnrollment
4
+ def initialize(object:)
5
+ @object = object
6
+ end
7
+
8
+ def call
9
+ fetch
10
+ end
11
+
12
+ private
13
+
14
+ attr_reader :object
15
+
16
+ def domain
17
+ ENV['CANVAS_DOMAIN']
18
+ end
19
+
20
+ def endpoint
21
+ [
22
+ protocol, domain, ':', port,
23
+ '/api/v1/accounts/',account_id,'/enrollments/',object.id
24
+ ].join('')
25
+ end
26
+
27
+ def use_ssl?
28
+ ENV['CANVAS_SSL'] == 'true'
29
+ end
30
+
31
+ def port
32
+ return '3000' if Rails.env == 'development'
33
+ return '443' if use_ssl?
34
+ '80'
35
+ end
36
+
37
+ def headers
38
+ { Authorization: "Bearer #{ENV['STRONGMIND_INTEGRATION_KEY']}" }
39
+ end
40
+
41
+ def fetch
42
+ PipelineService::HTTPClient.get(endpoint, headers: headers).parsed_response
43
+ end
44
+
45
+ def account_id
46
+ object.root_account.id
47
+ end
48
+
49
+ def protocol
50
+ return 'https://' if use_ssl?
51
+ 'http://'
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ module PipelineService
2
+ # This ugly thing lets us call the canvas user api
3
+ module Serializers
4
+ class Enrollment
5
+ include ::Api::V1::User
6
+ include BaseMethods
7
+
8
+ attr_accessor :services_enabled, :context, :current_user, :params, :request
9
+
10
+ def service_enabled?(service); @services_enabled.include? service; end
11
+
12
+ def avatar_image_url(*args); "avatar_image_url(#{args.first})"; end
13
+
14
+ def course_student_grades_url(course_id, user_id); ""; end
15
+
16
+ def course_user_url(course_id, user_id); ""; end
17
+
18
+ def initialize(object:)
19
+ @domain_root_account = ::Account.default
20
+ @params = {}
21
+ @request = OpenStruct.new
22
+ @object = object
23
+ @admin = PipelineService::Account.account_admin
24
+ end
25
+
26
+ def call
27
+ enrollment_json(@object, @admin, {})
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ module PipelineService
2
+ module Serializers
3
+ module Fetcher
4
+ # Will fetch a serializer with the same name as the object parameter.
5
+ # Raises a name error if the serializer doesn't exist.
6
+ # Maps any object with a class containing 'enrollment' to the enrollment serializer
7
+ def self.fetch(object:)
8
+ case object.class.to_s
9
+ when /Enrollment/
10
+ PipelineService::Serializers::Enrollment
11
+ else
12
+ "PipelineService::Serializers::#{object.class.to_s}".constantize
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ module PipelineService
2
+ module Serializers
3
+ # This ugly thing lets us call the canvas user api
4
+ class Submission
5
+ include ::Api
6
+ include ::Api::V1::Submission
7
+ include ActionView::Helpers
8
+ include ActionDispatch::Routing::UrlFor
9
+ include Rails.application.routes.url_helpers
10
+ include BaseMethods
11
+
12
+ def params;{};end
13
+
14
+ def initialize(object:)
15
+ default_url_options[:host] = host
16
+ @object = object
17
+ @admin = PipelineService::Account.account_admin
18
+ end
19
+
20
+ def request
21
+ super
22
+ end
23
+
24
+ def call
25
+ @current_user = @admin
26
+ submission_json(@object, @object.assignment, @admin, {}, nil, [])
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ module PipelineService
2
+ module Serializers
3
+ # This ugly thing lets us call the canvas user api
4
+ class User
5
+ include ::Api::V1::User
6
+ include BaseMethods
7
+
8
+ attr_accessor :services_enabled, :context, :current_user, :params, :request
9
+
10
+ def service_enabled?(service); @services_enabled.include? service; end
11
+
12
+ def avatar_image_url(*args); "avatar_image_url(#{args.first})"; end
13
+
14
+ def course_student_grades_url(course_id, user_id); ""; end
15
+
16
+ def course_user_url(course_id, user_id); ""; end
17
+
18
+ def initialize(object:)
19
+ @domain_root_account = ::Account.default
20
+ @params = {}
21
+ @request = OpenStruct.new
22
+ @object = object
23
+ @admin = PipelineService::Account.account_admin
24
+ end
25
+
26
+ def call
27
+ user_json(@object, @admin, {})
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,51 @@
1
+ # Usage:
2
+ # SettingsService.update_enrollment_setting(id: 1, setting: 'foo', value: 'bar')
3
+ module SettingsService
4
+ cattr_writer :canvas_domain
5
+
6
+ def self.update_settings(id:, setting:, value:, object:)
7
+ Commands::UpdateSettings.new(
8
+ id: id,
9
+ setting: setting,
10
+ value: value,
11
+ object: object
12
+ ).call
13
+ end
14
+
15
+ def self.update_enrollment_setting(id:, setting:, value:)
16
+ Commands::UpdateEnrollmentSetting.new(
17
+ id: id,
18
+ setting: setting,
19
+ value: value
20
+ ).call
21
+ end
22
+
23
+ def self.get_enrollment_settings(id:)
24
+ Commands::GetEnrollmentSettings.new(id: id).call
25
+ end
26
+
27
+ def self.get_settings(id:, object:)
28
+ Commands::GetSettings.new(id: id, object: object).call
29
+ end
30
+
31
+ def self.update_user_setting(id:, setting:, value:)
32
+ Commands::UpdateUserSetting.new(
33
+ id: id,
34
+ setting: setting,
35
+ value: value
36
+ ).call
37
+ end
38
+
39
+ def self.get_user_settings(id:)
40
+ Commands::GetUserSettings.new(id: id).call
41
+ end
42
+
43
+ def self.canvas_domain
44
+ @@canvas_domain || ENV['CANVAS_DOMAIN']
45
+ end
46
+
47
+ def self.query
48
+ Queries::ZeroGraderAudit.run
49
+ end
50
+
51
+ end
@@ -0,0 +1,68 @@
1
+ swagger: '2.0'
2
+ info:
3
+ description: This is User Settings
4
+ version: '1.0'
5
+ title: User Settings
6
+ contact:
7
+ email: devemail@example.com
8
+ host: localhost:3001
9
+ basePath: "/canvas_shim/settings_api/v1"
10
+ tags:
11
+ - name: user_setting
12
+ description: User Settings
13
+ schemes:
14
+ - http
15
+ paths:
16
+ "/users/{id}":
17
+ put:
18
+ tags:
19
+ - user_setting
20
+ summary: Adjust a setting on a user
21
+ description: ''
22
+ operationId: addUserSetting
23
+ consumes:
24
+ - application/json
25
+ produces:
26
+ - application/json
27
+ parameters:
28
+ - in: body
29
+ name: body
30
+ description: Settings to be stored on a user
31
+ required: true
32
+ schema:
33
+ "$ref": "#/definitions/User"
34
+ - name: id
35
+ in: path
36
+ description: ID of the user to apply the setting to
37
+ required: true
38
+ type: integer
39
+ format: int64
40
+ responses:
41
+ '405':
42
+ description: Invalid input
43
+ securityDefinitions:
44
+ api_key:
45
+ type: apiKey
46
+ name: api_key
47
+ in: header
48
+ definitions:
49
+ User:
50
+ type: object
51
+ properties:
52
+ accomodations:
53
+ type: array
54
+ items:
55
+ "$ref": "#/definitions/AccomodationTypes"
56
+ AccomodationTypes:
57
+ type: string
58
+ example: cat
59
+ ApiResponse:
60
+ type: object
61
+ properties:
62
+ code:
63
+ type: integer
64
+ format: int32
65
+ type:
66
+ type: string
67
+ message:
68
+ type: string