From 860d6b3b9fb1f5b21c235cb19f2362e4d9e51310 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 17 Oct 2023 21:26:18 +1100 Subject: [PATCH] feat: add ability to fetch tii viewer url --- app/api/similarity/task_similarity_api.rb | 27 +++++++++++- app/models/similarity/tii_task_similarity.rb | 2 +- .../turn_it_in/tii_action_get_view_url.rb | 40 ++++++++++++++++++ app/models/turn_it_in/tii_submission.rb | 9 ++++ test/api/breaks_api_test.rb | 4 -- test/helpers/auth_helper.rb | 11 ++++- test/helpers/tii_test_helper.rb | 4 +- test/models/task_similarity_test.rb | 42 +++++++++++++++++++ test/models/tii_model_test.rb | 11 +++++ 9 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 app/models/turn_it_in/tii_action_get_view_url.rb diff --git a/app/api/similarity/task_similarity_api.rb b/app/api/similarity/task_similarity_api.rb index 53655e890..da0658f80 100644 --- a/app/api/similarity/task_similarity_api.rb +++ b/app/api/similarity/task_similarity_api.rb @@ -48,7 +48,7 @@ class TaskSimilarityApi < Grape::API desc 'Get contents of a similarity by part index' params do optional :as_attachment, type: Boolean, desc: 'Whether or not to download file as attachment. Default is false.' - requires :idx, type: Integer, desc: 'Index of part to download. 0 is the first part, 1 is the second part.' + requires :idx, type: Integer, desc: 'Index of part to download. 0 is the first part, 1 is the second part. For MOSS Similarity' requires :id, type: Integer, desc: 'ID of similarity to download.' requires :task_id, type: Integer, desc: 'ID of task to download similarity for.' end @@ -90,5 +90,30 @@ class TaskSimilarityApi < Grape::API File.read(path) end + + desc 'Get viewer url for a turn it in similarity' + params do + requires :id, type: Integer, desc: 'ID of similarity to get viewer url for.' + requires :task_id, type: Integer, desc: 'ID of task to get similarity for.' + end + get '/tasks/:task_id/similarities/:id/viewer_url' do + unless authenticated? + error!({ error: "Not authorised to download details for task '#{params[:id]}'" }, 401) + end + task = Task.find(params[:task_id]) + + unless authorise? current_user, task, :view_plagiarism + error!({ error: "Not authorised to download details for task '#{params[:id]}'" }, 401) + end + + similarity = task.task_similarities.find(params[:id]) + + if similarity.present? && similarity.type == 'TiiTaskSimilarity' + result = similarity.create_viewer_url(current_user) + present result, with: Grape::Presenters::Presenter + else + error!({ error: "No details to download for task '#{params[:id]}'" }, 404) + end + end end end diff --git a/app/models/similarity/tii_task_similarity.rb b/app/models/similarity/tii_task_similarity.rb index 4d4dd79fc..db96fadee 100644 --- a/app/models/similarity/tii_task_similarity.rb +++ b/app/models/similarity/tii_task_similarity.rb @@ -3,5 +3,5 @@ class TiiTaskSimilarity < TaskSimilarity belongs_to :tii_submission - delegate :similarity_pdf_path, to: :tii_submission + delegate :similarity_pdf_path, :create_viewer_url, to: :tii_submission end diff --git a/app/models/turn_it_in/tii_action_get_view_url.rb b/app/models/turn_it_in/tii_action_get_view_url.rb new file mode 100644 index 000000000..8bf518c49 --- /dev/null +++ b/app/models/turn_it_in/tii_action_get_view_url.rb @@ -0,0 +1,40 @@ +# freeze_string_literal: true + +# Fetch the eula version and html from turn it in +class TiiActionGetViewUrl < TiiAction + delegate :status_sym, :status, :submission_id, :submitted_by_user, :task, :idx, :similarity_pdf_id, :similarity_pdf_path, :filename, to: :entity + + def description + "Get viewer url for #{self.filename} of #{self.task.student.username} from #{self.task.task_definition.abbreviation}" + end + + def run + result = fetch_view_url + if result.present? + self.complete = true + result + end + end + + # Connect to tii to get the latest eula details. + def fetch_view_url + exec_tca_call 'fetch view url' do + data = TCAClient::SimilarityViewerUrlSettings.new( + viewer_user_id: params[:viewer_tii_id], + locale: 'en-US', + viewer_default_permission_set: "INSTRUCTOR" + ) + + api_instance = TCAClient::SimilarityApi.new + report = api_instance.get_similarity_report_url( + TurnItIn.x_turnitin_integration_name, + TurnItIn.x_turnitin_integration_version, + submission_id, + data + ) + + # return the eula + report.viewer_url + end + end +end diff --git a/app/models/turn_it_in/tii_submission.rb b/app/models/turn_it_in/tii_submission.rb index b8fb9a382..18e27b381 100644 --- a/app/models/turn_it_in/tii_submission.rb +++ b/app/models/turn_it_in/tii_submission.rb @@ -54,6 +54,15 @@ def similarity_pdf_path File.join(path, FileHelper.sanitized_filename("#{id}-tii.pdf")) end + def create_viewer_url(user) + TiiActionGetViewUrl.create( + entity: self, + params: { + viewer_tii_id: user.username + } + ).perform + end + private # Delete the turn it in submission for a task diff --git a/test/api/breaks_api_test.rb b/test/api/breaks_api_test.rb index f27979723..97c03d2b6 100644 --- a/test/api/breaks_api_test.rb +++ b/test/api/breaks_api_test.rb @@ -5,10 +5,6 @@ class BreaksApiTest < ActiveSupport::TestCase include TestHelpers::AuthHelper include TestHelpers::JsonHelper - def app - Rails.application - end - #POST TEST def test_post_breaks teaching_period = FactoryBot.create(:teaching_period) diff --git a/test/helpers/auth_helper.rb b/test/helpers/auth_helper.rb index f82f61269..b81a7e4da 100644 --- a/test/helpers/auth_helper.rb +++ b/test/helpers/auth_helper.rb @@ -3,6 +3,13 @@ module TestHelpers # Authentication test helper # module AuthHelper + # + # Gets the Rails application need to call the api + # + def app + Rails.application + end + # # Gets an auth token for the provided user # @@ -13,10 +20,10 @@ def auth_token(user = User.first) return user.generate_authentication_token!().authentication_token end - # + # # Adds an authentication token and Username to the header # This prevents us from having to keep adding the :auth_token - # key to any GET/POST/PUT etc. data that is needed + # key to any GET/POST/PUT etc. data that is needed # def add_auth_header_for(user: User.first, username: nil, auth_token: nil) if username.present? diff --git a/test/helpers/tii_test_helper.rb b/test/helpers/tii_test_helper.rb index 3424b4f45..918aa87f7 100644 --- a/test/helpers/tii_test_helper.rb +++ b/test/helpers/tii_test_helper.rb @@ -59,9 +59,9 @@ def setup_tii_features_enabled exclude_preprints: true } ), - tenant: { + tenant: TCAClient::FeaturesTenant.new({ require_eula: true - }, + }), product_name: 'Turnitin Originality', access_options: [ 'NATIVE', diff --git a/test/models/task_similarity_test.rb b/test/models/task_similarity_test.rb index 9041ab1bc..d37746390 100644 --- a/test/models/task_similarity_test.rb +++ b/test/models/task_similarity_test.rb @@ -1,6 +1,10 @@ require "test_helper" class TaskSimilarityTest < ActiveSupport::TestCase + include Rack::Test::Methods + include TestHelpers::AuthHelper + include TestHelpers::JsonHelper + include TestHelpers::TiiTestHelper # Test that when you create a plagiarism match link, that a moss test needs the other task def test_other_details @@ -107,4 +111,42 @@ def test_similarity_from_task ensure task&.project&.unit&.destroy end + + def test_fetch_viewer_url + task = FactoryBot.create(:task) + + sim = TiiTaskSimilarity.create( + task: task, + pct: 10, + flagged: true, + tii_submission: TiiSubmission.create!( + task: task, + idx: 0, + filename: 'test.doc', + status: :created, + submitted_by_user: task.unit.main_convenor_user, + submission_id: 1223 + ) + ) + + add_auth_header_for(user: task.unit.main_convenor_user) + + # This will post to get the viewer url + viewer_url_request = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/submissions/1223/viewer-url"). + with(tii_headers). + to_return(status: 200, body: TCAClient::SimilarityViewerUrlResponse.new(viewer_url: 'https://viewer.url').to_hash.to_json, headers: {} + ) + + get "/api/tasks/#{task.id}/similarities/#{sim.id}/viewer_url" + assert_equal 200, last_response.status + assert last_response.body.include? "https://viewer.url" + + add_auth_header_for(user: task.project.student) + get "/api/tasks/#{task.id}/similarities/#{sim.id}/viewer_url" + assert_equal 401, last_response.status + + sim.tii_submission.update!(submission_id: nil) + sim.destroy! + task.destroy! + end end diff --git a/test/models/tii_model_test.rb b/test/models/tii_model_test.rb index 94f042f5c..dd41064e0 100644 --- a/test/models/tii_model_test.rb +++ b/test/models/tii_model_test.rb @@ -464,6 +464,17 @@ def test_tii_process assert_requested download_pdf_request, times: 1 assert File.exist?(subm.similarity_pdf_path) + # Get the viewer url + viewer_url_request = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/submissions/1223/viewer-url"). + with(tii_headers). + to_return(status: 200, body: TCAClient::SimilarityViewerUrlResponse.new(viewer_url: 'https://viewer.url').to_hash.to_json, headers: {} + ) + + viewer_act = subm.create_viewer_url(subm.task.tutor) + + assert_requested viewer_url_request, times: 1 + assert_equal 'https://viewer.url', viewer_act + # Now for submission 1 # Stub ssubmission 1 as well subm_status_req = stub_request(:get, "https://#{ENV['TCA_HOST']}/api/v1/submissions/1222").