Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add holds by source report #919

Merged
merged 1 commit into from
Mar 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/controllers/report_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ReportController < ApplicationController
protect_from_forgery with: :exception

include ThesisHelper
include HoldHelper

def empty_theses
term = params[:graduation] ? params[:graduation].to_s : 'all'
Expand Down Expand Up @@ -49,6 +50,17 @@ def student_submitted_theses
@list = report.list_student_submitted_metadata subset
end

def holds_by_source
term = params[:graduation] ? params[:graduation].to_s : 'all'
@this_term = 'all terms'
@this_term = term.in_time_zone('Eastern Time (US & Canada)').strftime('%b %Y') if term != 'all'
holds = Hold.all.includes(:thesis).includes(:hold_source).includes(thesis: :users).includes(thesis: :authors)
@terms = Report.new.extract_terms holds
@hold_sources = HoldSource.pluck(:source).uniq.sort
term_filtered = filter_holds_by_term holds
@list = filter_holds_by_source term_filtered
end

def index
report = Report.new
@terms = Thesis.pluck(:grad_date).uniq.sort
Expand Down
20 changes: 18 additions & 2 deletions app/helpers/hold_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,28 @@ def render_hold_history_field(field_name, field_value)
field_value = 'n/a' if field_value.nil?

# For foreign key fields, return a link to the record
if field_name == 'thesis_id' && thesis = Thesis.find_by(id: field_value)
if field_name == 'thesis_id' && (thesis = Thesis.find_by(id: field_value))
field_value = link_to thesis.title, admin_thesis_path(field_value)
elsif field_name == 'hold_source_id' && hold_source = HoldSource.find_by(id: field_value)
elsif field_name == 'hold_source_id' && (hold_source = HoldSource.find_by(id: field_value))
field_value = link_to hold_source.source, admin_hold_source_path(field_value)
end

field_value
end

def filter_holds_by_term(holds)
if params[:graduation] && params[:graduation] != 'all'
return holds.where('theses.grad_date = ?', params[:graduation]).references(:thesis)
end

holds
end

def filter_holds_by_source(holds)
if params[:hold_source] && params[:hold_source] != 'all'
return holds.where('hold_sources.source = ?', params[:hold_source]).references(:thesis)
end

holds
end
end
1 change: 1 addition & 0 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def processor
can :term, Report
can :empty_theses, Report
can :expired_holds, Report
can :holds_by_source, Report
can :student_submitted_theses, Report

can %i[read update], Thesis
Expand Down
8 changes: 7 additions & 1 deletion app/models/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,14 @@ def empty_theses_record(collection)
result
end

# This assumes a couple of things: first, that all items in a collection should be instances of the same model, and
# second, that the model of any non-thesis collections belongs_to the Thesis model.
def extract_terms(collection)
collection.pluck(:grad_date).uniq.sort
if collection.first.is_a? Thesis
collection.pluck(:grad_date).uniq.sort
else
collection.includes(:thesis).pluck(:grad_date).uniq.sort
end
end

def record_empty_theses(collection)
Expand Down
14 changes: 14 additions & 0 deletions app/views/report/_hold.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<tr>
<td><%= link_to title_helper(hold.thesis), edit_admin_thesis_path(hold.thesis.id) %></td>
<td>
<% hold.thesis.authors.each do |author| %>
<%= author.user.display_name %><br>
<% end %>
</td>
<td><%= hold.thesis.graduation_month[...3] %> <%= hold.thesis.graduation_year %></td>
<td><%= hold.hold_source.source %></td>
<td><%= hold.status %></td>
<td><%= hold.date_requested %></td>
<td><%= hold.date_start %></td>
<td><%= hold.date_end %></td>
</tr>
3 changes: 3 additions & 0 deletions app/views/report/_hold_empty.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<tr>
<td colspan="8">There are no holds for the given term.</td>
</tr>
31 changes: 31 additions & 0 deletions app/views/report/_holds_by_source_filter.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<%= form_tag(nil, method: "get") do %>
<div class="multi-form-tag">
<label>
Include only theses from:
<select name="graduation">
<option value="all">All terms</option>
<% @terms.each do |term| %>
<option value="<%= term %>"<%= ' selected="selected"'.html_safe if params[:graduation].to_s == term.to_s %>>
<%= term.in_time_zone('Eastern Time (US & Canada)').strftime('%b %Y') %>
</option>
<% end %>
</select>
</label>
</div>

<div class="multi-form-tag">
<label>
Filter by hold source:
<select name="hold_source">
<option value="all">All sources</option>
<% @hold_sources.each do |source| %>
<option value="<%= source %>"<%= ' selected="selected"'.html_safe if params[:hold_source].to_s == source.to_s %>>
<%= source %>
</option>
<% end %>
</select>
</label>
</div>

<%= submit_tag('Apply filters', class: 'btn button-primary') %>
<% end %>
32 changes: 32 additions & 0 deletions app/views/report/holds_by_source.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<%= content_for(:title, "Thesis Reporting | MIT Libraries") %>

<div class="layout-3q1q layout-band">
<div class="col3q">
<h3 class="title title-page">Holds by source for <%= @this_term %></h3>

<%= render 'holds_by_source_filter' %>

<table class="table" summary="This table presents a list of holds filtered by source."
title="Student submitted metadata">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Author(s)</th>
<th scope="col">Grad date</th>
<th scope="col">Hold source</th>
<th scope="col">Status</th>
<th scope="col">Date requested</th>
<th scope="col">Start date</th>
<th scope="col">End date</th>
</tr>
</thead>
<tbody>
<%= render(partial: 'hold', collection: @list) || render('hold_empty') %>
</tbody>
</table>
</div>

<aside class="content-sup col1q-r">
<%= render 'shared/report_submenu' %>
</aside>
</div>
3 changes: 3 additions & 0 deletions app/views/shared/_report_submenu.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<% if can?(:files, Report) %>
<li><%= link_to("Files without purpose", report_files_path) %></li>
<% end %>
<% if can?(:holds_by_source, Report) %>
<li><%= link_to("Holds by source", report_holds_by_source_path) %></li>
<% end %>
<% if can?(:expired_holds, Report) %>
<li><%= link_to("Unreleased holds which have ended", report_expired_holds_path) %></li>
<% end %>
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
get 'report/empty_theses', to: 'report#empty_theses', as: 'report_empty_theses'
get 'report/expired_holds', to: 'report#expired_holds', as: 'report_expired_holds'
get 'report/files', to: 'report#files', as: 'report_files'
get 'report/holds_by_source', to: 'report#holds_by_source', as: 'report_holds_by_source'
get 'report/proquest_files', to: 'report#proquest_files', as: 'report_proquest_files'
get 'report/student_submitted_theses', to: 'report#student_submitted_theses', as: 'report_student_submitted_theses'
get 'report/term', to: 'report#term', as: 'report_term'
Expand Down
111 changes: 109 additions & 2 deletions test/controllers/report_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ def create_thesis_with_whodunnit(user)
test 'default files report is empty' do
sign_in users(:processor)
get report_files_path
assert_select 'table tbody td', text: 'There are no files without an assigned purpose within the selected term.', count: 1
assert_select 'table tbody td', text: 'There are no files without an assigned purpose within the selected term.',
count: 1
end

test 'files have no default purpose, and appear on the files report' do
Expand All @@ -362,7 +363,8 @@ def create_thesis_with_whodunnit(user)
get report_files_path
assert_select 'table tbody td', text: 'a_pdf.pdf', count: 2
get report_files_path, params: { graduation: '2018-09-01' }
assert_select 'table tbody td', text: 'There are no files without an assigned purpose within the selected term.', count: 1
assert_select 'table tbody td', text: 'There are no files without an assigned purpose within the selected term.',
count: 1
end

test 'files disappear from files report when a purpose is set' do
Expand Down Expand Up @@ -561,4 +563,109 @@ def create_thesis_with_whodunnit(user)
get report_student_submitted_theses_path, params: { graduation: '2018-09-01' }
assert_select 'table tbody td', text: 'There are no student-submitted theses for the given term.', count: 1
end

# ~~~~~~~~~~~~~~~ Holds by source report ~~~~~~~~~~~~~~~~
test 'anonymous users cannot see holds by source report' do
# Note that nobody is signed in.
get report_holds_by_source_path
assert_response :redirect
end

test 'basic users cannot see holds by source report' do
sign_in users(:basic)
get report_holds_by_source_path
assert_redirected_to '/'
follow_redirect!
assert_select 'div.alert', text: 'Not authorized.', count: 1
end

test 'submitters cannot see holds by source report' do
sign_in users(:transfer_submitter)
get report_holds_by_source_path
assert_redirected_to '/'
follow_redirect!
assert_select 'div.alert', text: 'Not authorized.', count: 1
end

test 'processors can see holds by sourcereport' do
sign_in users(:processor)
get report_holds_by_source_path
assert_response :success
end

test 'thesis_admins can see holds by source report' do
sign_in users(:thesis_admin)
get report_holds_by_source_path
assert_response :success
end

test 'admins can see holds by source report' do
sign_in users(:admin)
get report_holds_by_source_path
assert_response :success
end

# ~~~~~~~~~~~~~~~ Holds by source report ~~~~~~~~~~~~~~~~
test 'holds by source report shows holds with any source by default' do
hold_count = Hold.all.count

sign_in users(:processor)
get report_holds_by_source_path
assert_select 'table tbody tr', count: hold_count
end

test 'holds by source report allows filtering by term' do
hold_count = Hold.all.count
term_count = Hold.joins(:thesis).where('theses.grad_date = ?', '2017-09-01').count
assert_not_equal hold_count, term_count

# Add 1 to the select counts for the 'All terms'/'All sources' options
term_select_count = Report.new.extract_terms(Hold.all).count + 1

sign_in users(:processor)
get report_holds_by_source_path
assert_select 'table tbody tr', count: hold_count
assert_select 'select[name="graduation"] option', count: term_select_count

# Now request the queue with a filter applied, and see the correct record count
get report_holds_by_source_path, params: { graduation: '2017-09-01' }
assert_select 'table tbody tr', count: term_count
end

test 'holds by source report allows filtering by hold source' do
hold_count = Hold.all.count
source_count = Hold.where(hold_source_id: "#{hold_sources(:tlo).id}").count

# Add 1 to the select counts for the 'All terms'/'All sources' options
source_select_count = HoldSource.pluck(:source).uniq.count + 1

sign_in users(:processor)
get report_holds_by_source_path
assert_select 'table tbody tr', count: hold_count
assert_select 'select[name="hold_source"] option', count: source_select_count

# Now request the queue with a filter applied, and the correct record count
get report_holds_by_source_path, params: { hold_source: 'technology licensing office' }
assert_select 'table tbody tr', count: source_count
end

test 'holds by source report allows filtering by both term and publication status' do
hold_count = Hold.all.count
source_count = Hold.joins(:thesis).where('theses.grad_date = ?', '2017-09-01')
.where(hold_source_id: "#{hold_sources(:tlo).id}").count

# Add 1 to the select counts for the 'All terms'/'All sources' options
term_select_count = Report.new.extract_terms(Hold.all).count + 1
source_select_count = HoldSource.pluck(:source).uniq.count + 1

sign_in users(:processor)
get report_holds_by_source_path
assert_select 'table tbody tr', count: hold_count
assert_select 'select[name="graduation"] option', count: term_select_count
assert_select 'select[name="hold_source"] option', count: source_select_count

# Now request the queue with both filters applied, and see the correct record count
get report_holds_by_source_path, params: { graduation: '2017-09-01', hold_source: 'technology licensing office' }
assert_select 'table tbody tr', count: source_count
end
end