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