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

Feature/jplag implementation #447

Open
wants to merge 15 commits into
base: development
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ GEM
faraday-net_http (3.1.0)
net-http
ffi (1.17.0-aarch64-linux-gnu)
ffi (1.17.0-x86_64-linux-gnu)
fugit (1.11.0)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
Expand Down Expand Up @@ -265,6 +266,8 @@ GEM
nio4r (2.7.3)
nokogiri (1.16.5-aarch64-linux)
racc (~> 1.4)
nokogiri (1.16.5-x86_64-linux)
racc (~> 1.4)
observer (0.1.2)
orm_adapter (0.5.0)
parallel (1.24.0)
Expand Down Expand Up @@ -490,6 +493,7 @@ GEM

PLATFORMS
aarch64-linux
x86_64-linux

DEPENDENCIES
better_errors
Expand Down
3 changes: 2 additions & 1 deletion app/api/entities/task_definition_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ def staff?(my_role)
expose :has_task_sheet?, as: :has_task_sheet
expose :has_task_resources?, as: :has_task_resources
expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) }
expose :has_jplag_report?, as: :has_jplag_report, if: ->(unit, options) { staff?(options[:my_role]) }
expose :is_graded
expose :max_quality_pts
expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) }
expose :assessment_enabled, if: ->(unit, options) { staff?(options[:my_role]) }
expose :moss_language, if: ->(unit, options) { staff?(options[:my_role]) }
expose :jplag_language, if: ->(unit, options) { staff?(options[:my_role]) }
end
end
21 changes: 3 additions & 18 deletions app/api/similarity/entities/task_similarity_entity.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
module Similarity
module Entities
class TaskSimilarityEntity < Grape::Entity
def staff?(my_role)
Role.teaching_staff_ids.include?(my_role.id) unless my_role.nil?
end

expose :id
expose :type
Expand All @@ -13,32 +10,20 @@ def staff?(my_role)
similarity.ready_for_viewer?
end

expose :parts do |similarity, options|
expose :parts do |similarity|
path = similarity.file_path
has_resource = path.present? && File.exist?(path)

result = [
{
idx: 0,
format: if has_resource
similarity.type == 'MossTaskSimilarity' ? 'html' : 'pdf'
similarity.type == 'JplagTaskSimilarity' ? 'html' : 'pdf'
end,
description: "#{similarity.student.name} (#{similarity.student.username}) - #{similarity.pct}%"
description: "#{similarity.other_student.name} (#{similarity.other_student.username}) - #{similarity.pct}% similarity"
}
]

# For moss similarity, show staff other student details
if similarity.type == 'MossTaskSimilarity' && staff?(options[:my_role])
other_path = similarity.other_similarity&.file_path
has_other_resource = other_path.present? && File.exist?(other_path)

result << {
idx: 1,
format: has_other_resource ? 'html' : nil,
description: "Match: #{similarity.other_student&.name} (#{similarity.other_student&.username}) - #{similarity.other_similarity&.pct}"
}
end

result
end
end
Expand Down
49 changes: 45 additions & 4 deletions app/api/task_definitions_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class TaskDefinitionsApi < Grape::API
requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed'
optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment'
optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image for overseer'
optional :moss_language, type: String, desc: 'The language to use for code similarity checks'
optional :jplag_language, type: String, desc: 'The language to use for code similarity checks'
end
end
post '/units/:unit_id/task_definitions/' do
Expand Down Expand Up @@ -61,7 +61,7 @@ class TaskDefinitionsApi < Grape::API
:max_quality_pts,
:assessment_enabled,
:overseer_image_id,
:moss_language
:jplag_language
)

task_params[:unit_id] = unit.id
Expand Down Expand Up @@ -110,7 +110,7 @@ class TaskDefinitionsApi < Grape::API
optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed'
optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment'
optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image name for overseer'
optional :moss_language, type: String, desc: 'The language to use for code similarity checks'
optional :jplag_language, type: String, desc: 'The language to use for code similarity checks'
end
end
put '/units/:unit_id/task_definitions/:id' do
Expand Down Expand Up @@ -138,7 +138,7 @@ class TaskDefinitionsApi < Grape::API
:max_quality_pts,
:assessment_enabled,
:overseer_image_id,
:moss_language
:jplag_language
)

task_params[:upload_requirements] = JSON.parse(params[:task_def][:upload_requirements]) unless params[:task_def][:upload_requirements].nil?
Expand Down Expand Up @@ -614,4 +614,45 @@ class TaskDefinitionsApi < Grape::API

stream_file path
end

desc 'Download the JPLAG report for a given task'
params do
requires :unit_id, type: Integer, desc: 'The unit to download JPLAG report for'
requires :task_def_id, type: Integer, desc: 'The task definition to get the JPLAG report of'
end
get '/units/:unit_id/task_definitions/:task_def_id/jplag_report' do
unit = Unit.find(params[:unit_id])
task_def = unit.task_definitions.find(params[:task_def_id])
unless authorise? current_user, unit, :download_jplag_report
error!({ error: 'Not authorised to download JPLAG reports of unit' }, 403)
end
logger.debug "This is the has_jplag_report? #{task_def.has_jplag_report?}"
if task_def.has_jplag_report?
path = FileHelper.task_jplag_report_path(unit, task_def)
header['Content-Disposition'] = "attachment; filename=#{task_def.abbreviation}-jplag-report.zip"
else
path = Rails.root.join('public', 'resources', 'FileNotFound.pdf')
content_type 'application/pdf'
header['Content-Disposition'] = 'attachment; filename=FileNotFound.pdf'
end
header['Access-Control-Expose-Headers'] = 'Content-Disposition'
content_type 'application/octet-stream'
stream_file path
end

desc 'Get hasJplagReport boolean for a given task'
params do
requires :unit_id, type: Integer, desc: 'The unit to get JPLAG report for'
requires :task_def_id, type: Integer, desc: 'The task definition to get the JPLAG report of'
end
get '/units/:unit_id/task_definitions/:task_def_id/has_jplag_report' do
unit = Unit.find(params[:unit_id])
task_def = unit.task_definitions.find(params[:task_def_id])

unless authorise? current_user, unit, :download_jplag_report
error!({ error: 'Not authorised to download JPLAG reports of unit' }, 403)
end

task_def.has_jplag_report?
end
end
12 changes: 12 additions & 0 deletions app/helpers/file_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,16 @@ def student_portfolio_path(unit, username, create = true)
File.join(student_portfolio_dir(unit, username, create), FileHelper.sanitized_filename("#{username}-portfolio.pdf"))
end

def task_jplag_report_dir(unit)
file_server = Doubtfire::Application.config.jplag_report_dir
dst = "#{file_server}/#{unit.code}-#{unit.id}/" # trust the server config and passed in type for paths
dst
end

def task_jplag_report_path(unit, task)
File.join(task_jplag_report_dir(unit), FileHelper.sanitized_filename("#{task.abbreviation}-result.zip"))
end

def comment_attachment_path(task_comment, attachment_extension)
"#{File.join(student_work_dir(:comment, task_comment.task), "#{task_comment.id.to_s}#{attachment_extension}")}"
end
Expand Down Expand Up @@ -658,4 +668,6 @@ def line_wrap(path, width: 160)
module_function :known_extension?
module_function :pages_in_pdf
module_function :line_wrap
module_function :task_jplag_report_dir
module_function :task_jplag_report_path
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class MossTaskSimilarity < TaskSimilarity
class JplagTaskSimilarity < TaskSimilarity
belongs_to :other_task, class_name: 'Task'

def file_path
Expand Down Expand Up @@ -28,7 +28,7 @@ def file_path
end

def other_similarity
MossTaskSimilarity.where(task_id: other_task.id, other_task_id: task.id).first unless other_task.nil?
JplagTaskSimilarity.where(task_id: other_task.id, other_task_id: task.id).first unless other_task.nil?
end

def other_student
Expand Down
6 changes: 3 additions & 3 deletions app/models/similarity/task_definition_similarity_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
# Provides moss and tii similarity features in task definitions
module TaskDefinitionSimilarityModule
def moss_similarities?
MossTaskSimilarity.joins(:task).where('tasks.task_definition_id' => id).count > 0
JplagTaskSimilarity.joins(:task).where('tasks.task_definition_id' => id).count > 0
end

def clear_related_plagiarism
# delete old plagiarism links
logger.info "Deleting old links for task definition #{id} - #{abbreviation}"
MossTaskSimilarity.joins(:task).where('tasks.task_definition_id' => id).find_each do |plnk|
pair = MossTaskSimilarity.find_by(id: plnk.id)
JplagTaskSimilarity.joins(:task).where('tasks.task_definition_id' => id).find_each do |plnk|
pair = JplagTaskSimilarity.find_by(id: plnk.id)
pair.destroy! if pair.present?
end
end
Expand Down
Loading
Loading