Skip to content

Commit

Permalink
Add holds by source report
Browse files Browse the repository at this point in the history
Why these changes are being introduced:

We need to be able to see the holds for a given degree period,
filtered by hold source.

Relevant ticket(s):

https://mitlibraries.atlassian.net/browse/ETD-462

How this addresses that need:

This adds a report of holds that allows filtering on thesis
grad date and hold source.

Side effects of this change:

* Report#extract_terms now checks for the type of items in the
collection, so as to accommodate non-thesis collections.
  • Loading branch information
jazairi committed Feb 25, 2022
1 parent 85b0186 commit ffc39d3
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 5 deletions.
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
@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
22 changes: 20 additions & 2 deletions app/helpers/hold_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@ 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.joins(:thesis).where('theses.grad_date = ?',
params[:graduation])
end

holds
end

def filter_holds_by_source(holds)
if params[:hold_source] && params[:hold_source] != 'all'
return holds.joins(:hold_source).where('hold_sources.source = ?',
params[:hold_source])
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.joins(: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_end %></td>
<td><%= hold.date_released %></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">End date</th>
<th scope="col">Date released</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 tbfody 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

0 comments on commit ffc39d3

Please sign in to comment.