diff --git a/app/views/shared/_report_submenu.html.erb b/app/views/shared/_report_submenu.html.erb
index 3c7c8c7e..8321f239 100644
--- a/app/views/shared/_report_submenu.html.erb
+++ b/app/views/shared/_report_submenu.html.erb
@@ -8,6 +8,9 @@
<% if can?(:select, Thesis) %>
<%= link_to("Theses with co-authors", thesis_deduplicate_path) %>
<% end %>
+ <% if can?(:files, Report) %>
+
<%= link_to("Files without purpose", report_files_path) %>
+ <% end %>
diff --git a/config/routes.rb b/config/routes.rb
index 39ca704e..18dc4e81 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -20,6 +20,7 @@
end
get 'report', to: 'report#index', as: 'report_index'
+ get 'report/files', to: 'report#files', as: 'report_files'
get 'report/term', to: 'report#term', as: 'report_term'
get 'thesis/confirm', to: 'thesis#confirm', as: 'thesis_confirm'
get 'thesis/deduplicate', to: 'thesis#deduplicate', as: 'thesis_deduplicate'
diff --git a/test/controllers/report_controller_test.rb b/test/controllers/report_controller_test.rb
index eca9af23..0a3b0171 100644
--- a/test/controllers/report_controller_test.rb
+++ b/test/controllers/report_controller_test.rb
@@ -1,6 +1,23 @@
require 'test_helper'
class ReportControllerTest < ActionDispatch::IntegrationTest
+ def attach_files(tr, th)
+ # Ideally our fixtures would have already-attached files, but they do not
+ # yet. So we attach two files to a transfer and thesis record, to prepare
+ # for tests with an accurate set of file attachments.
+ f1 = Rails.root.join('test', 'fixtures', 'files', 'a_pdf.pdf')
+ f2 = Rails.root.join('test', 'fixtures', 'files', 'a_pdf.pdf')
+ tr.files.attach(io: File.open(f1), filename: 'a_pdf.pdf')
+ tr.files.attach(io: File.open(f2), filename: 'a_pdf.pdf')
+ tr.save
+ tr.reload
+ th.files.attach(tr.files.first.blob)
+ th.files.attach(tr.files.second.blob)
+ th.save
+ th.reload
+ end
+
+ # ~~~~~~~~~~~~~~~~~~~~ Report dashboard ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test 'summary report exists' do
sign_in users(:admin)
get report_index_path
@@ -120,4 +137,91 @@ class ReportControllerTest < ActionDispatch::IntegrationTest
assert_select '.card-overall .message', text: '2 thesis records', count: 1
assert_response :success
end
+
+ # ~~~~~~~~~~~~~~~~~~~~ Files without purpose report ~~~~~~~~~~~~~~~~~~~~~~~~
+ test 'files report exists' do
+ sign_in users(:admin)
+ get report_files_path
+ assert_response :success
+ end
+
+ test 'anonymous users are prompted to log in by files report' do
+ # Note that nobody is signed in.
+ get report_files_path
+ assert_response :redirect
+ end
+
+ test 'basic users cannot see files report' do
+ sign_in users(:basic)
+ get report_files_path
+ assert_redirected_to '/'
+ follow_redirect!
+ assert_select 'div.alert', text: 'Not authorized.', count: 1
+ end
+
+ test 'submitters cannot see files report' do
+ sign_in users(:transfer_submitter)
+ get report_files_path
+ assert_redirected_to '/'
+ follow_redirect!
+ assert_select 'div.alert', text: 'Not authorized.', count: 1
+ end
+
+ test 'processors can see files report' do
+ sign_in users(:processor)
+ get report_files_path
+ assert_response :success
+ end
+
+ test 'thesis_admins can see files report' do
+ sign_in users(:thesis_admin)
+ get report_files_path
+ assert_response :success
+ end
+
+ test 'admins can see files report' do
+ sign_in users(:admin)
+ get report_files_path
+ assert_response :success
+ end
+
+ 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
+ end
+
+ test 'files have no default purpose, and appear on the files report' do
+ sign_in users(:processor)
+ xfer = transfers(:valid)
+ thesis = theses(:one)
+ attach_files(xfer, thesis)
+ get report_files_path
+ assert_select 'table tbody td', text: 'a_pdf.pdf', count: 2
+ end
+
+ test 'files report can be filtered by term' do
+ sign_in users(:processor)
+ xfer = transfers(:valid)
+ thesis = theses(:one)
+ attach_files(xfer, thesis)
+ 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
+ end
+
+ test 'files disappear from files report when a purpose is set' do
+ sign_in users(:processor)
+ xfer = transfers(:valid)
+ thesis = theses(:one)
+ attach_files(xfer, thesis)
+ get report_files_path
+ assert_select 'table tbody td', text: 'a_pdf.pdf', count: 2
+ file = thesis.files.first
+ file.purpose = 0
+ file.save
+ get report_files_path
+ assert_select 'table tbody td', text: 'a_pdf.pdf', count: 1
+ end
end