Add subscription show to LTI DataServices

closes PLAT-4761

Test Plan:
 - see that a call to this endpoint will show a sub

Change-Id: Ifc299aebe5cfbadaf82a1970f75ad182ffa31b29
Reviewed-on: https://gerrit.instructure.com/206489
Reviewed-by: Xander Moffatt <xmoffatt@instructure.com>
Tested-by: Jenkins
QA-Review: Marc Phillips <mphillips@instructure.com>
Product-Review: Marc Phillips <mphillips@instructure.com>
This commit is contained in:
Marc Phillips 2019-08-23 10:37:12 -06:00
parent 78a25bf4e8
commit 1f2394e982
6 changed files with 101 additions and 28 deletions

View File

@ -16,12 +16,55 @@
# with this program. If not, see <http://www.gnu.org/licenses/>.
module Lti
# @API Data Services
#
# Data service api for tools.
#
# @model DataServiceSubscription
# {
# "id": "DataServiceSubscription",
# "description": "A subscription to a data service live event.",
# "properties": {
# "ContextId": {
# "description": "The id of the context for the subscription.",
# "example": "8ADadf-asdfas-asdfas-asdfaew",
# "type": "string"
# },
# "ContextType": {
# "description": "The type of context for the subscription. Must be 'assignment', or 'root_account'",
# "example": "root_account",
# "type": "string"
# },
# "EventTypes": {
# "description": "Array of strings representing the event types for the subscription.",
# "example": ["asset_accessed"],
# "type": "array",
# "items": {"type": "string"}
# },
# "Format": {
# "description": "Format to deliver the live events. Must be 'live-event' or 'caliper'.",
# "example": "caliper",
# "type": "string"
# },
# "TransportMetadata": {
# "description": "An object with a single key: 'Url'.",
# "example": "{\n\t\"Url\":\"sqs.example\"}",
# "type": "string"
# },
# "TransportType": {
# "description": "The type of transport for the event. Must be either 'sqs' or 'https'.",
# "example": "sqs",
# "type": "string"
# }
# }
# }
class DataServicesController < ApplicationController
include Ims::Concerns::AdvantageServices
MIME_TYPE = 'application/vnd.canvas.dataservices+json'.freeze
ACTION_SCOPE_MATCHERS = {
create: all_of(TokenScopes::LTI_CREATE_DATA_SERVICE_SUBSCRIPTION_SCOPE)
create: all_of(TokenScopes::LTI_CREATE_DATA_SERVICE_SUBSCRIPTION_SCOPE),
show: all_of(TokenScopes::LTI_SHOW_DATA_SERVICE_SUBSCRIPTION_SCOPE)
}.freeze.with_indifferent_access
rescue_from Lti::SubscriptionsValidator::InvalidContextType do
@ -34,7 +77,7 @@ module Lti
before_action :verify_service_configured
# @API Create a Webhook Subscription
# @API Create a Data Services Event Subscription
# Creates a webook subscription for the specified event type and
# context.
#
@ -57,6 +100,8 @@ module Lti
#
# @argument subscription[TransportType] [Required, String]
# Must be either 'sqs' or 'https'.
#
# @returns DataServiceSubscription
def create
sub = params.require(:subscription)
SubscriptionsValidator.validate_subscription_context!(sub)
@ -64,6 +109,15 @@ module Lti
forward_service_response(response)
end
# @API Show a Data Services Event Subscription
# Show existing Data Services Event Subscription
#
# @returns DataServiceSubscription
def show
response = Services::LiveEventsSubscriptionService.show(jwt_body, params.require(:id))
forward_service_response(response)
end
private
def scopes_matcher
@ -81,8 +135,9 @@ module Lti
end
def jwt_body
dk_id = developer_key.global_id.to_s
{
sub: SecureRandom.uuid,
sub: "#{dk_id}:#{context.uuid}",
DeveloperKey: developer_key.global_id.to_s,
RootAccountId: context.global_id,
RootAccountUUID: context.uuid

View File

@ -2347,6 +2347,7 @@ CanvasRails::Application.routes.draw do
# Data Services Service
scope(controller: 'lti/data_services') do
post "/accounts/:account_id/data_services", action: :create, as: :data_services_create
get "/accounts/:account_id/data_services/:id", action: :show, as: :data_services_show
end
# Names and Roles Provisioning (NRPS) v2 Service

View File

@ -55,7 +55,8 @@ module Schemas::Lti
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
"https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly",
"https://canvas.instructure.com/lti/public_jwk/scope/update",
"https://canvas.instructure.com/lti/data_services/scope/create"
"https://canvas.instructure.com/lti/data_services/scope/create",
"https://canvas.instructure.com/lti/data_services/scope/show"
].freeze
}
}.freeze,

View File

@ -29,6 +29,7 @@ class TokenScopes
LTI_NRPS_V2_SCOPE = "https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly".freeze
LTI_UPDATE_PUBLIC_JWK_SCOPE = "https://canvas.instructure.com/lti/public_jwk/scope/update".freeze
LTI_CREATE_DATA_SERVICE_SUBSCRIPTION_SCOPE = "https://canvas.instructure.com/lti/data_services/scope/create".freeze
LTI_SHOW_DATA_SERVICE_SUBSCRIPTION_SCOPE = "https://canvas.instructure.com/lti/data_services/scope/show".freeze
LTI_SCOPES = {
LTI_AGS_LINE_ITEM_SCOPE => I18n.t("Can create and view assignment data in the gradebook associated with the tool."),
LTI_AGS_LINE_ITEM_READ_ONLY_SCOPE => I18n.t("Can view assignment data in the gradebook associated with the tool."),
@ -36,7 +37,8 @@ class TokenScopes
LTI_AGS_SCORE_SCOPE => I18n.t("Can create and update submission results for assignments associated with the tool."),
LTI_NRPS_V2_SCOPE => I18n.t("Can retrieve user data associated with the context the tool is installed in."),
LTI_UPDATE_PUBLIC_JWK_SCOPE => I18n.t("Can update public jwk for LTI services."),
LTI_CREATE_DATA_SERVICE_SUBSCRIPTION_SCOPE => I18n.t("Can create subscription to data service data.")
LTI_CREATE_DATA_SERVICE_SUBSCRIPTION_SCOPE => I18n.t("Can create subscription to data service data."),
LTI_SHOW_DATA_SERVICE_SUBSCRIPTION_SCOPE => I18n.t("Can show subscription to data service data.")
}.freeze
LTI_AGS_SCOPES = [ LTI_AGS_LINE_ITEM_SCOPE, LTI_AGS_LINE_ITEM_READ_ONLY_SCOPE, LTI_AGS_RESULT_READ_ONLY_SCOPE, LTI_AGS_SCORE_SCOPE ].freeze

View File

@ -22,28 +22,28 @@ require File.expand_path(File.dirname(__FILE__) + '/ims/concerns/lti_services_sh
require_dependency "lti/public_jwk_controller"
describe Lti::DataServicesController do
include WebMock::API
include_context 'advantage services context'
let(:subscription) do
{
ContextId: root_account.uuid,
ContextType: 'root_account',
EventTypes: ['discussion_topic_created'],
Format: 'live-event',
TransportMetadata: { Url: 'sqs.example' },
TransportType: 'sqs'
}
end
before do
allow(Canvas::Security::ServicesJwt).to receive(:encryption_secret).and_return('setecastronomy92' * 2)
allow(Canvas::Security::ServicesJwt).to receive(:signing_secret).and_return('donttell' * 10)
allow(HTTParty).to receive(:send).and_return(double(body: subscription, code: 200))
end
describe '#create' do
include WebMock::API
include_context 'advantage services context'
let(:subscription) do
{
ContextId: root_account.uuid,
ContextType: 'root_account',
EventTypes: ['discussion_topic_created'],
Format: 'live-event',
TransportMetadata: { Url: 'sqs.example' },
TransportType: 'sqs'
}
end
before do
allow(Canvas::Security::ServicesJwt).to receive(:encryption_secret).and_return('setecastronomy92' * 2)
allow(Canvas::Security::ServicesJwt).to receive(:signing_secret).and_return('donttell' * 10)
allow(HTTParty).to receive(:send).and_return(double(body: subscription, code: 200))
end
it_behaves_like 'lti services' do
let(:action) { :create }
let(:expected_mime_type) { described_class::MIME_TYPE }
@ -53,4 +53,15 @@ describe Lti::DataServicesController do
end
end
end
describe '#show' do
it_behaves_like 'lti services' do
let(:action) { :show }
let(:expected_mime_type) { described_class::MIME_TYPE }
let(:scope_to_remove) { "https://canvas.instructure.com/lti/data_services/scope/show"}
let(:params_overrides) do
{ subscription: subscription, account_id: root_account.id, id: 'testid' }
end
end
end
end

View File

@ -28,11 +28,14 @@ shared_context 'advantage services context' do
dk
end
let(:access_token_scopes) do
%w(https://purl.imsglobal.org/spec/lti-ags/scope/lineitem
%w(
https://purl.imsglobal.org/spec/lti-ags/scope/lineitem
https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly
https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly
https://canvas.instructure.com/lti/public_jwk/scope/update
https://canvas.instructure.com/lti/data_services/scope/create).join(' ')
https://canvas.instructure.com/lti/data_services/scope/create
https://canvas.instructure.com/lti/data_services/scope/show
).join(' ')
end
let(:access_token_signing_key) { Canvas::Security.encryption_key }
let(:test_request_host) { 'test.host' }