Skip to content

Commit d770ab6

Browse files
author
Andrew Butterfield
committed
Add presenter to membership service controller index action
fixes PLAT-1343 Test plan: * Using a course with sufficient users hit the following endpoint /api/lti/courses/:course_id/membership_service using a user's access token * The endpoint supports three query params page per_page role * At the moment the role parameter is preserved in the nextPage url but doesn't have any effect on what the endpoint returns * Ensure that the nextPage url query params are preserved and that the page param increments properly * Ensure that per_page defaults to Api.per_page and that it cannot exceed Api.max_per_page * Ensure that the json objects that are returned conform to the format detailed here: http://www.imsglobal.org/lti/model/mediatype/application/vnd/ims/lis/v2/membershipcontainer%2Bjson/index.html#Introduction * Ensure that the list of users returned by the membership service includes only those users that the requesting user has permission to view Change-Id: I9d25dce6678e5bf04719469a3c38392f3f0d1d68 Reviewed-on: https://gerrit.instructure.com/75821 Reviewed-by: Nathan Mills <nathanm@instructure.com> Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Product-Review: Andrew Butterfield <abutterfield@instructure.com>
1 parent 0ed94c5 commit d770ab6

2 files changed

Lines changed: 142 additions & 3 deletions

File tree

app/controllers/lti/membership_service_controller.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,18 @@ class MembershipServiceController < ApplicationController
2020
before_filter :require_user
2121

2222
def index
23-
render json: { hello: :world }
23+
@page = MembershipService::PagePresenter.new(@context,
24+
@current_user,
25+
request.base_url,
26+
membership_service_params)
27+
render json: @page
28+
end
29+
30+
private
31+
32+
def membership_service_params
33+
keys = %w(role page per_page)
34+
params.select { |k,_| keys.include?(k) }
2435
end
2536
end
2637
end

spec/controllers/lti/membership_service_controller_spec.rb

Lines changed: 130 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,137 @@ module Lti
2626
end
2727

2828
describe "#index" do
29-
it 'requires a user' do
29+
context 'without access token' do
30+
it 'requires a user' do
31+
get 'index', course_id: @course.id
32+
assert_unauthorized
33+
end
34+
end
35+
36+
context 'with access token' do
37+
before(:each) do
38+
pseudonym(@teacher)
39+
@teacher.save!
40+
token = @teacher.access_tokens.create!(purpose: 'test').full_token
41+
@request.headers['Authorization'] = "Bearer #{token}"
42+
end
43+
44+
it 'outputs the expected data in the expected format at the top level' do
45+
get 'index', course_id: @course.id
46+
hash = json_parse.with_indifferent_access
47+
expect(hash.keys.size).to eq(6)
48+
49+
expect(hash.fetch(:@id)).to be_nil
50+
expect(hash.fetch(:@type)).to eq 'Page'
51+
expect(hash.fetch(:@context)).to eq 'http://purl.imsglobal.org/ctx/lis/v2/MembershipContainer'
52+
expect(hash.fetch(:differences)).to be_nil
53+
expect(hash.fetch(:nextPage)).to be_nil
54+
expect(hash.fetch(:pageOf)).not_to be_nil
55+
end
56+
57+
it 'outputs the expected data in the expected format at the container level' do
58+
get 'index', course_id: @course.id
59+
hash = json_parse.with_indifferent_access
60+
container = hash[:pageOf]
61+
62+
expect(container.size).to eq 5
63+
expect(container.fetch(:@id)).to be_nil
64+
expect(container.fetch(:@type)).to eq 'LISMembershipContainer'
65+
expect(container.fetch(:@context)).to eq 'http://purl.imsglobal.org/ctx/lis/v2/MembershipContainer'
66+
expect(container.fetch(:membershipPredicate)).to eq 'http://www.w3.org/ns/org#membership'
67+
expect(container.fetch(:membershipSubject)).not_to be_nil
68+
end
69+
70+
it 'outputs the expected data in the expected format at the context level' do
71+
get 'index', course_id: @course.id
72+
hash = json_parse.with_indifferent_access
73+
@course.reload
74+
context = hash[:pageOf][:membershipSubject]
75+
76+
expect(context.size).to eq 5
77+
expect(context.fetch(:@id)).to be_nil
78+
expect(context.fetch(:@type)).to eq 'Context'
79+
expect(context.fetch(:name)).to eq @course.name
80+
expect(context.fetch(:contextId)).to eq @course.lti_context_id
81+
expect(context.fetch(:membership)).not_to be_nil
82+
end
83+
84+
it 'outputs the expected data in the expected format at the membership level' do
85+
get 'index', course_id: @course.id
86+
hash = json_parse.with_indifferent_access
87+
@teacher.reload
88+
memberships = hash[:pageOf][:membershipSubject][:membership]
89+
90+
expect(memberships.size).to eq 1
91+
92+
membership = memberships[0]
93+
94+
expect(membership.size).to eq 4
95+
expect(membership.fetch(:@id)).to be_nil
96+
expect(membership.fetch(:status)).to eq IMS::LIS::Statuses::SimpleNames::Active
97+
expect(membership.fetch(:role)).to match_array([IMS::LIS::Roles::Context::URNs::Instructor])
98+
99+
member = membership.fetch(:member)
100+
expect(member.fetch(:@id)).to be_nil
101+
expect(member.fetch(:name)).to eq @teacher.name
102+
expect(member.fetch(:img)).to eq @teacher.avatar_image_url
103+
expect(member.fetch(:email)).to eq @teacher.email
104+
expect(member.fetch(:familyName)).to eq @teacher.last_name
105+
expect(member.fetch(:givenName)).to eq @teacher.first_name
106+
expect(member.fetch(:resultSourcedId)).to be_nil
107+
expect(member.fetch(:sourcedId)).to be_nil
108+
expect(member.fetch(:userId)).to eq(@teacher.lti_context_id)
109+
end
110+
end
111+
end
112+
end
113+
114+
context 'course with multiple enrollments' do
115+
before(:each) do
116+
course_with_teacher
117+
@course.enroll_user(@teacher, 'TeacherEnrollment', enrollment_state: 'active')
118+
@ta = user_model
119+
@course.enroll_user(@ta, 'TaEnrollment', enrollment_state: 'active')
120+
@student = user_model
121+
@course.enroll_user(@student, 'StudentEnrollment', enrollment_state: 'active')
122+
123+
pseudonym(@teacher)
124+
@teacher.save!
125+
token = @teacher.access_tokens.create!(purpose: 'test').full_token
126+
@request.headers['Authorization'] = "Bearer #{token}"
127+
end
128+
129+
describe '#as_json' do
130+
it 'provides the right next_page url when no page/per_page/role params are given' do
131+
Api.stubs(:per_page).returns(1)
30132
get 'index', course_id: @course.id
31-
assert_unauthorized
133+
hash = json_parse.with_indifferent_access
134+
135+
uri = URI(hash.fetch(:nextPage))
136+
expect(uri.scheme).to eq 'http'
137+
expect(uri.host).to eq 'test.host'
138+
expect(uri.path).to eq "/api/lti/courses/#{@course.id}/membership_service"
139+
expect(uri.query).to eq 'page=2&per_page=1'
140+
end
141+
142+
it 'provides the right next_page url when page/per_page/role params are given' do
143+
Api.stubs(:per_page).returns(1)
144+
get 'index', course_id: @course.id, page: 2, per_page: 1, role: 'Instructor'
145+
hash = json_parse.with_indifferent_access
146+
147+
uri = URI(hash.fetch(:nextPage))
148+
expect(uri.scheme).to eq 'http'
149+
expect(uri.host).to eq 'test.host'
150+
expect(uri.path).to eq "/api/lti/courses/#{@course.id}/membership_service"
151+
expect(uri.query).to eq 'page=3&per_page=1&role=Instructor'
152+
end
153+
154+
it 'returns nil for the next page url when the last page in the collection was requested' do
155+
Api.stubs(:per_page).returns(1)
156+
get 'index', course_id: @course.id, page: 3, per_page: 1, role: 'Instructor'
157+
hash = json_parse.with_indifferent_access
158+
159+
expect(hash.fetch(:nextPage)).to be_nil
32160
end
33161
end
34162
end

0 commit comments

Comments
 (0)