diff --git a/app/controllers/validation_controller.rb b/app/controllers/validation_controller.rb
new file mode 100644
index 0000000..cac9d7b
--- /dev/null
+++ b/app/controllers/validation_controller.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class ValidationController < ApplicationController
+ def index
+ @terms = Term.joins(:detections).uniq
+ end
+
+ def term
+ @term = Term.find(params[:id])
+ @detectors = Detector.all
+ @categories = Category.all
+ end
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 0451a9a..2bef2fa 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -22,6 +22,10 @@ def initialize(user)
# Allow all authenticated users to view reports
can :view, :report
+
+ # Allow all authenticted users to perform validation work
+ can :manage, :validation
+ can :manage, Validation
# End of Rules for all authenticated user with no additional roles required
# Rules for admins
diff --git a/app/views/layouts/_site_nav.html.erb b/app/views/layouts/_site_nav.html.erb
index a0686b8..f3ca92b 100644
--- a/app/views/layouts/_site_nav.html.erb
+++ b/app/views/layouts/_site_nav.html.erb
@@ -13,6 +13,9 @@
<% if can? :index, Term %>
<%= link_to('Admin', admin_root_path, class: 'nav-item') %>
<% end %>
+ <% if can? :index, Validation %>
+ <%= link_to('Validate', validate_path, class: 'nav-item') %>
+ <% end %>
<% if can? :view, :playground %>
<%= link_to('Playground', '/playground', class: 'nav-item') %>
<% end %>
diff --git a/app/views/validation/index.html.erb b/app/views/validation/index.html.erb
new file mode 100644
index 0000000..ea13aa6
--- /dev/null
+++ b/app/views/validation/index.html.erb
@@ -0,0 +1,23 @@
+<%= content_for(:title, "TACOS Validation") %>
+
+
Validation index
+
+This would be the page which lists terms - which have tripped a detector and have been categorized - which have not
+yet been validated by a user.
+
+
+
+
+ ID |
+ Phrase |
+
+
+
+ <% @terms.each do |t| %>
+
+ <%= t.id %> |
+ <%= link_to(t.phrase, validate_term_path(t) ) %> |
+
+ <% end %>
+
+
diff --git a/app/views/validation/term.html.erb b/app/views/validation/term.html.erb
new file mode 100644
index 0000000..40dcd4f
--- /dev/null
+++ b/app/views/validation/term.html.erb
@@ -0,0 +1,63 @@
+<%= content_for(:title, "TACOS Validation") %>
+
+<%= link_to('Back to validation index', validate_path) %>
+
+Validation form
+
+
+
+Please note: The information below is not currently filtered
+for only current detections; all detections across the history of the application
+are represented. This will need to be adjusted in the future.
+
+Detection result
+
+
+
+
+ Detector |
+ Result |
+
+
+
+ <% @detectors.each do |d| %>
+
+ <%= d.name %> |
+
+ <% if @term.detections.pluck(:detector_id).include?(d.id) %>
+ Detection
+ <% else %>
+
+ <% end %>
+ |
+
+ <% end %>
+
+
+
+Categorization result
+
+
+
+
+ Category |
+ Score |
+
+
+
+ <% @categories.each do |c| %>
+
+ <%= c.name %> |
+
+ <% if @term.categorizations.pluck(:category_id).include?(c.id) %>
+ <%= @term.categorizations.find_by(category_id: c.id).confidence %>
+ <% else %>
+
+ <% end %>
+ |
+
+ <% end %>
+
+
diff --git a/config/routes.rb b/config/routes.rb
index de42371..f62fec8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -38,6 +38,10 @@
get '/report', to: 'report#index'
get '/report/algorithm_metrics', to: 'report#algorithm_metrics'
+ # Validation interface
+ get '/validate', to: 'validation#index'
+ get '/validate/:id', to: 'validation#term', as: 'validate_term'
+
# Defines the root path route ("/")
root to: 'static#index'
end
diff --git a/test/controllers/validation_controller_test.rb b/test/controllers/validation_controller_test.rb
new file mode 100644
index 0000000..f17307c
--- /dev/null
+++ b/test/controllers/validation_controller_test.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+
+class ValidationControllerTest < ActionDispatch::IntegrationTest
+ # Access to validation index
+ test 'validation index is not accessible without authentication' do
+ get validate_path
+
+ assert_redirected_to '/'
+ follow_redirect!
+
+ assert_select 'div.alert', text: 'Please sign in to continue', count: 1
+ end
+
+ test 'validation index is accessible to users with no special access' do
+ sign_in users(:basic)
+ get validate_path
+
+ assert_response :success
+ end
+
+ test 'validation index is accessible to users with the admin flag set' do
+ sign_in users(:admin)
+ get validate_path
+
+ assert_response :success
+ end
+
+ test 'unauthenticated users do not see a nav link to validation' do
+ get root_path
+
+ assert_select 'a.nav-item', text: 'Validate', count: 0
+ end
+
+ test 'Users with no special access do see a nav link to validation' do
+ sign_in users(:basic)
+ get root_path
+
+ assert_select 'a.nav-item', text: 'Validate', count: 1
+ end
+
+ test 'Users with the admin flag set do see a nav link to validation' do
+ sign_in users(:admin)
+ get root_path
+
+ assert_select 'a.nav-item', text: 'Validate', count: 1
+ end
+
+ # Access to validation form
+ test 'validation form is not accessible without authentication' do
+ get validate_term_path(terms(:hi))
+
+ assert_redirected_to '/'
+ follow_redirect!
+
+ assert_select 'div.alert', text: 'Please sign in to continue', count: 1
+ end
+
+ test 'validation form is accessible to users with no special access' do
+ sign_in users(:basic)
+ get validate_term_path(terms(:hi))
+
+ assert_response :success
+ end
+
+ test 'validation form is accessible to users with the admin flag set' do
+ sign_in users(:admin)
+ get validate_term_path(terms(:hi))
+
+ assert_response :success
+ end
+
+ # Validation form contents
+ test 'validation form includes a table row for every detector' do
+ sign_in users(:basic)
+ get validate_term_path(terms(:hi))
+
+ assert_select 'tr.detector-result', count: Detector.count
+ end
+
+ test 'validation form includes a table row for every category' do
+ sign_in users(:basic)
+ get validate_term_path(terms(:hi))
+
+ assert_select 'tr.category-result', count: Category.count
+ end
+end