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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +21 -0
- data/app/assets/config/canvas_shim_manifest.js +2 -0
- data/app/assets/javascripts/canvas_shim/application.js +13 -0
- data/app/assets/stylesheets/canvas_shim/application.css +15 -0
- data/app/controllers/canvas_shim/application_controller.rb +12 -0
- data/app/controllers/canvas_shim/settings_api/swagger_controller.rb +11 -0
- data/app/controllers/canvas_shim/settings_api/v1/users_controller.rb +27 -0
- data/app/deploy/canvas_shim_asset_uploader.rb +19 -0
- data/app/helpers/canvas_shim/application_helper.rb +4 -0
- data/app/jobs/canvas_shim/application_job.rb +4 -0
- data/app/mailers/canvas_shim/application_mailer.rb +6 -0
- data/app/models/canvas_shim/application_record.rb +5 -0
- data/app/services/courses_service.rb +5 -0
- data/app/services/courses_service/commands/distribute_due_dates.rb +50 -0
- data/app/services/courses_service/commands/distribute_due_dates/scheduler.rb +70 -0
- data/app/services/grades_service.rb +33 -0
- data/app/services/grades_service/account.rb +13 -0
- data/app/services/grades_service/commands/zero_out_assignment_grades.rb +73 -0
- data/app/services/grades_service/commands/zero_out_assignment_grades_rollback.rb +38 -0
- data/app/services/pipeline_service.rb +27 -0
- data/app/services/pipeline_service/account.rb +9 -0
- data/app/services/pipeline_service/api/publish.rb +53 -0
- data/app/services/pipeline_service/commands/publish.rb +44 -0
- data/app/services/pipeline_service/commands/publish_events.rb +17 -0
- data/app/services/pipeline_service/endpoints/pipeline.rb +62 -0
- data/app/services/pipeline_service/endpoints/pipeline/message_builder.rb +75 -0
- data/app/services/pipeline_service/events/emitter.rb +56 -0
- data/app/services/pipeline_service/events/graded_out_event.rb +31 -0
- data/app/services/pipeline_service/events/http_client.rb +14 -0
- data/app/services/pipeline_service/events/responders/sis.rb +66 -0
- data/app/services/pipeline_service/events/subscription.rb +11 -0
- data/app/services/pipeline_service/http_client.rb +21 -0
- data/app/services/pipeline_service/logger.rb +39 -0
- data/app/services/pipeline_service/pipeline_client.rb +41 -0
- data/app/services/pipeline_service/serializers/assignment.rb +55 -0
- data/app/services/pipeline_service/serializers/base_methods.rb +33 -0
- data/app/services/pipeline_service/serializers/canvas_api_enrollment.rb +55 -0
- data/app/services/pipeline_service/serializers/enrollment.rb +31 -0
- data/app/services/pipeline_service/serializers/fetcher.rb +17 -0
- data/app/services/pipeline_service/serializers/submission.rb +30 -0
- data/app/services/pipeline_service/serializers/user.rb +31 -0
- data/app/services/settings_service.rb +51 -0
- data/app/services/settings_service/api_docs.yml +68 -0
- data/app/services/settings_service/assignment.rb +24 -0
- data/app/services/settings_service/assignment_repository.rb +89 -0
- data/app/services/settings_service/auth_middleware.rb +19 -0
- data/app/services/settings_service/auth_token.rb +21 -0
- data/app/services/settings_service/authenticator_stub.rb +9 -0
- data/app/services/settings_service/commands/get_enrollment_settings.rb +17 -0
- data/app/services/settings_service/commands/get_settings.rb +34 -0
- data/app/services/settings_service/commands/get_user_settings.rb +18 -0
- data/app/services/settings_service/commands/update_enrollment_setting.rb +22 -0
- data/app/services/settings_service/commands/update_settings.rb +38 -0
- data/app/services/settings_service/commands/update_user_setting.rb +21 -0
- data/app/services/settings_service/enrollment.rb +28 -0
- data/app/services/settings_service/queries/zero_grader_audit.rb +6 -0
- data/app/services/settings_service/repository.rb +93 -0
- data/app/services/settings_service/school.rb +26 -0
- data/app/services/settings_service/student_assignment.rb +24 -0
- data/app/services/settings_service/student_assignment_repository.rb +116 -0
- data/app/services/settings_service/submission.rb +24 -0
- data/app/services/settings_service/user.rb +28 -0
- data/app/views/layouts/canvas_shim/application.html.erb +14 -0
- data/config/initializers/hash.rb +17 -0
- data/config/initializers/string.rb +9 -0
- data/config/routes.rb +9 -0
- data/lib/canvas_shim.rb +5 -0
- data/lib/canvas_shim/engine.rb +12 -0
- data/lib/canvas_shim/version.rb +3 -0
- data/lib/tasks/canvas_shim_tasks.rake +7 -0
- metadata +214 -0
@@ -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
|