diff --git a/.rubocop.yml b/.rubocop.yml index 57717201..98c72451 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -69,3 +69,7 @@ Layout/IndentFirstHashElement: Style/WordArray: Exclude: - 'config/application.rb' + +Naming/PredicateName: + Exclude: + - 'app/models/user.rb' diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1f47860f..3d128890 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -16,7 +16,7 @@ def current_user? def patron return unless current_user? - @patron ||= Patron.new(patron_info_response) + @patron ||= Patron.new(patron_info_response, current_user) end def patron_or_group diff --git a/app/models/patron.rb b/app/models/patron.rb index 17085d71..f1669169 100644 --- a/app/models/patron.rb +++ b/app/models/patron.rb @@ -2,7 +2,7 @@ # Class to model Patron information class Patron - attr_reader :record + attr_reader :record, :user CHARGE_LIMIT_THRESHOLD = 25_000 @@ -21,8 +21,9 @@ class Patron 'MXFEE-NO25' => 'Fee borrower' }.freeze - def initialize(record) + def initialize(record, user = nil) @record = record + @user = user end def key @@ -156,6 +157,7 @@ def to_partial_path def borrow_direct_requests return [] if proxy_borrower? # Proxies can't submit borrow direct requests, so don't check. + return [] unless user&.has_borrow_direct_access? BorrowDirectRequests.new(self).requests end diff --git a/app/models/user.rb b/app/models/user.rb index 864e5d3b..89b49ae3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,13 +3,21 @@ # :nodoc: class User include ActiveModel::Model - attr_accessor :username, :patron_key, :shibboleth + attr_accessor :username, :patron_key, :privgroups, :shibboleth # FIXME: This is temporary code and can be removed after everyone who has logged into -dev # has logged out and logged in. def initialize(attributes) - super(attributes.with_indifferent_access.slice(:username, :patron_key, :shibboleth)) + super(attributes.with_indifferent_access.slice(:username, :patron_key, :privgroups, :shibboleth)) end alias shibboleth? shibboleth + + def has_borrow_direct_access? + ((privgroups || []) & Settings.auth.borrow_direct_privgroups).any? + end + + def has_eresources_access? + ((privgroups || []) & Settings.auth.eresources_privgroups).any? + end end diff --git a/app/views/patron/_patron.html.erb b/app/views/patron/_patron.html.erb index 1ffeff2c..49434a2a 100644 --- a/app/views/patron/_patron.html.erb +++ b/app/views/patron/_patron.html.erb @@ -18,4 +18,14 @@
Email:
<%= patron.email %>
<% end %> + + <% unless current_user.has_eresources_access? || patron.proxy_borrower? %> +
eResource access:
+
In-library only
+ <% end %> + + <% if current_user.privgroups %> +
Privgroups:
+
<%= current_user.privgroups.inspect %>
+ <% end %> diff --git a/config/deploy.rb b/config/deploy.rb index 270cc724..8b5f3e8a 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -26,3 +26,4 @@ # update shared_configs before restarting app before 'deploy:restart', 'shared_configs:update' +set :branch, 'privgroups' diff --git a/config/initializers/warden.rb b/config/initializers/warden.rb index cb085293..eb4a1155 100644 --- a/config/initializers/warden.rb +++ b/config/initializers/warden.rb @@ -9,7 +9,7 @@ def authenticate! response = SymphonyClient.new.login_by_sunetid(uid) if response && response['key'] - u = { username: uid, patron_key: response['key'], shibboleth: true } + u = { username: uid, patron_key: response['key'], privgroups: privgroups, shibboleth: true } success!(u) else fail!('Could not log in') @@ -21,6 +21,14 @@ def authenticate! def uid env['uid'] end + + def privgroups + if env['eduPersonEntitlement'].present? + env['eduPersonEntitlement'].split(';') + else + [] + end + end end Warden::Strategies.add(:development_shibboleth_stub) do @@ -32,7 +40,7 @@ def authenticate! response = SymphonyClient.new.login_by_sunetid(uid) if response && response['key'] - u = { username: uid, patron_key: response['key'] } + u = { username: uid, patron_key: response['key'], privgroups: privgroups } success!(u) else fail!('Could not log in') @@ -44,6 +52,14 @@ def authenticate! def uid ENV['uid'] end + + def privgroups + if ENV['privgroups'].present? + ENV['privgroups'].split(';') + else + Settings.auth.default_privgroups + end + end end Warden::Strategies.add(:library_id) do @@ -55,7 +71,7 @@ def authenticate! response = SymphonyClient.new.login(params['library_id'], params['pin']) if response['patronKey'] - u = { username: params['library_id'], patron_key: response['patronKey'] } + u = { username: params['library_id'], patron_key: response['patronKey'], privgroups: [] } success!(u) else fail!('Could not log in') diff --git a/config/settings.yml b/config/settings.yml index 9a20438a..13873f5f 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -13,4 +13,16 @@ ACCESS_SERVICES_EMAIL: greencirc@stanford.edu RECAPTCHA: SITE_KEY: 6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy SECRET_KEY: 6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx - + +auth: + default_privgroups: [] + borrow_direct_privgroups: + - stanford:stanford + - stanford:academic + eresources_privgroups: + - stanford:stanford + - stanford:academic + - stanford:administrative + - organization:sumc + - sulair:proxy-access + - lane:proxy-access diff --git a/config/settings/development.yml b/config/settings/development.yml index e69de29b..7b93205a 100644 --- a/config/settings/development.yml +++ b/config/settings/development.yml @@ -0,0 +1,3 @@ +auth: + default_privgroups: + - stanford:stanford diff --git a/spec/models/patron_spec.rb b/spec/models/patron_spec.rb index 3a584296..9f6bb539 100644 --- a/spec/models/patron_spec.rb +++ b/spec/models/patron_spec.rb @@ -8,10 +8,15 @@ { key: '1', fields: fields - }.with_indifferent_access + }.with_indifferent_access, + mock_user ) end + let(:mock_user) do + instance_double(User, has_borrow_direct_access?: true) + end + let(:fields) do { firstName: 'Student', @@ -347,6 +352,14 @@ it 'includes requests that come from the BorrowDirectRequests class' do expect(patron.requests.last[:key]).to be 2 end + + context 'without borrow direct access' do + let(:mock_user) { instance_double(User, has_borrow_direct_access?: false) } + + it 'excludes requests from BorrowDirect' do + expect(patron.requests).to have_attributes(length: 1).and(match([have_attributes(key: 1)])) + end + end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 31a611c6..21389ccb 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -18,4 +18,32 @@ expect(user).to be_shibboleth end end + + describe '#has_borrow_direct_access?' do + context 'with a user in an appropriate privgroup' do + let(:user_attributes) { { username: 'sunetid', patron_key: '123', privgroups: ['stanford:stanford'] } } + + it 'is has access' do + expect(user).to have_borrow_direct_access + end + end + + it 'is has no access' do + expect(user).not_to have_borrow_direct_access + end + end + + describe '#has_eresources_access?' do + context 'with a user in an appropriate privgroup' do + let(:user_attributes) { { username: 'sunetid', patron_key: '123', privgroups: ['stanford:stanford'] } } + + it 'is has access' do + expect(user).to have_eresources_access + end + end + + it 'is has no access' do + expect(user).not_to have_eresources_access + end + end end diff --git a/spec/views/patron/_patron.html.erb_spec.rb b/spec/views/patron/_patron.html.erb_spec.rb index 3281763d..c41f6c6b 100644 --- a/spec/views/patron/_patron.html.erb_spec.rb +++ b/spec/views/patron/_patron.html.erb_spec.rb @@ -19,6 +19,7 @@ **patron_options ) end + let(:user) { instance_double(User, has_eresources_access?: true, privgroups: []) } before do controller.singleton_class.class_eval do @@ -26,10 +27,13 @@ def patron; end - helper_method :patron + def current_user; end + + helper_method :patron, :current_user end allow(view).to receive(:patron).and_return(patron) + allow(view).to receive(:current_user).and_return(user) end describe 'Privileges expire' do @@ -51,4 +55,24 @@ def patron; end it { expect(rendered).to have_css('dt', text: 'Privileges expire') } end end + + describe 'eresources access' do + before { render } + + context 'when the user has access' do + it { expect(rendered).not_to have_css('dt', text: 'eResource access') } + end + + context 'when the user is a proxy borrower' do + let(:patron_options) { { proxy_borrower?: true } } + + it { expect(rendered).not_to have_css('dt', text: 'eResource access') } + end + + context 'when the user has no access' do + let(:user) { instance_double(User, has_eresources_access?: false, privgroups: []) } + + it { expect(rendered).to have_css('dt', text: 'eResource access') } + end + end end diff --git a/spec/views/summaries/index.html.erb_spec.rb b/spec/views/summaries/index.html.erb_spec.rb index e65fd0f7..6b1d1d74 100644 --- a/spec/views/summaries/index.html.erb_spec.rb +++ b/spec/views/summaries/index.html.erb_spec.rb @@ -27,17 +27,22 @@ ) end + let(:user) { instance_double(User, has_eresources_access?: true, privgroups: []) } + before do controller.singleton_class.class_eval do protected def patron_or_group; end - helper_method :patron_or_group + def current_user; end + + helper_method :patron_or_group, :current_user end stub_template 'shared/_navigation.html.erb' => 'Navigation' allow(view).to receive(:patron_or_group).and_return(patron) + allow(view).to receive(:current_user).and_return(user) end context 'when the patron is barred' do