Skip to content
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Doubtfire requires multiple environment variables that help define settings abou
| `DF_AUTH_METHOD` | The authentication method you would like Doubtfire to use. Possible values are `database` for standard authentication with the database, `ldap` | `database` |
| | for [LDAP](https://www.freebsd.org/doc/en/articles/ldap-auth/), `aaf` for [AAF Rapid Connect](https://rapid.aaf.edu.au/), or `SAML2` for [SAML2.0 auth](https://en.wikipedia.org/wiki/SAML_2.0). | |
| `DF_STUDENT_WORK_DIR` | The directory to store uploaded student work for processing. | `student_work` |
| `DF_ARCHIVE_DIR` | The directory to move archived unit files to, and access from. | `DF_STUDENT_WORK_DIR/archive` |
| `DF_INSTITUTION_NAME` | The name of your institution running Doubtfire. | _University of Foo_ |
| `DF_INSTITUTION_EMAIL_DOMAIN` | The email domain from which emails are sent to and from in your institution. | `doubtfire.com` |
| `DF_INSTITUTION_HOST` | The host running the Doubtfire instance. | `localhost:3000` |
Expand Down
10 changes: 4 additions & 6 deletions app/api/submission/portfolio_evidence_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ def self.logger
optional :as_attachment, type: Boolean, desc: 'Whether or not to download file as attachment. Default is false.'
end
get '/projects/:id/task_def_id/:task_definition_id/submission' do
project = Project.find(params[:id])
task_definition = project.unit.task_definitions.find(params[:task_definition_id])
project = Project.eager_load(:unit).find(params[:id])
task_definition = project.unit.task_definitions.select(:id, :name, :abbreviation).find(params[:task_definition_id])

# check the user can put this task
unless authorise? current_user, project, :get_submission
Expand All @@ -86,14 +86,12 @@ def self.logger

task = project.task_for_task_definition(task_definition)

evidence_loc = task.portfolio_evidence_path
student = task.project.student
unit = task.project.unit
evidence_loc = task.final_pdf_path

if task.processing_pdf?
evidence_loc = Rails.root.join('public/resources/AwaitingProcessing.pdf')
filename = 'AwaitingProcessing.pdf'
elsif evidence_loc.nil?
elsif evidence_loc.nil? || !File.exist?(evidence_loc)
evidence_loc = Rails.root.join('public/resources/FileNotFound.pdf')
filename = 'FileNotFound.pdf'
else
Expand Down
79 changes: 58 additions & 21 deletions app/helpers/file_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,7 @@ def sanitized_filename(filename)
end

def task_file_dir_for_unit(unit, create = true)
file_server = Doubtfire::Application.config.student_work_dir
dst = "#{file_server}/" # trust the server config and passed in type for paths
dst << sanitized_path("#{unit.code}-#{unit.id}", 'TaskFiles') << '/'
dst = unit_work_root(unit) << 'TaskFiles/'

FileUtils.mkdir_p dst if create && (!Dir.exist? dst)

Expand Down Expand Up @@ -176,6 +174,30 @@ def student_work_root
Doubtfire::Application.config.student_work_dir
end

def archive_root
Doubtfire::Application.config.archive_dir
end

# Get the path to the unit root - will take into consideration if archived
#
# @param [Unit] unit - the unit to get the root path for
# @param [Boolean] archived - whether to use the archived property (true/false)
# or force it to be the archived path (:force)
def unit_work_root(unit, archived: true)
dst = if (unit.archived && archived) || (archived == :force)
"#{archive_root}/"
else
"#{student_work_root}/"
end

dst << sanitized_path("#{unit.code}-#{unit.id}") << '/'
end

def project_work_root(project, archived: true, username: nil)
username = project.student.username.to_s if username.nil?
unit_work_root(project.unit, archived: archived) << sanitized_path(username) << '/'
end

#
# Generates a path for storing student work
# type = [:new, :in_process, :done, :pdf, :plagarism]
Expand All @@ -187,18 +209,17 @@ def student_work_dir(type = nil, task = nil, create = true)
file_server = Doubtfire::Application.config.student_work_dir
dst = "#{file_server}/" # trust the server config and passed in type for paths

if !(type.nil? || task.nil?)
if !(type.nil? || task.nil?) # we have task and type
if [:discussion, :pdf, :comment].include? type
dst << sanitized_path("#{task.project.unit.code}-#{task.project.unit.id}", task.project.student.username.to_s, type.to_s) << '/'
dst = project_work_root(task.project) << sanitized_path(type.to_s) << '/'
elsif [:done, :plagarism].include? type
dst << sanitized_path("#{task.project.unit.code}-#{task.project.unit.id}", task.project.student.username.to_s, type.to_s, task.id.to_s) << '/'
dst = project_work_root(task.project) << sanitized_path(type.to_s, task.id.to_s) << '/'
else # new and in_process -- just have task id
# Add task id to dst if we want task
dst << "#{type}/#{task.id}/"
end
elsif !type.nil?
elsif !type.nil? # have type but not task
if [:in_process, :new].include? type
# Add task id to dst if we want task
dst << "#{type}/"
else
raise 'Error in request to student work directory'
Expand All @@ -211,27 +232,40 @@ def student_work_dir(type = nil, task = nil, create = true)
dst
end

def dir_for_unit_code_and_id(unit_code, unit_id, create = true)
file_server = Doubtfire::Application.config.student_work_dir
dst = "#{file_server}/" # trust the server config and passed in type for paths
def dir_for_unit_code_and_id(unit_code, unit_id, create: true, archived: false)
dst = if archived
"#{archive_root}/"
else
"#{student_work_root}/"
end

dst << sanitized_path("#{unit_code}-#{unit_id}")

FileUtils.mkdir_p dst if create && !Dir.exist?(dst)

dst
end

def unit_dir(unit, create = true)
dir_for_unit_code_and_id(unit.code, unit.id, create)
def unit_dir(unit, create: true, archived: true)
dir_for_unit_code_and_id(unit.code, unit.id, create: create, archived: archived == :force || (archived && unit.archived))
end

def root_portfolio_dir
file_server = Doubtfire::Application.config.student_work_dir
def root_portfolio_dir(archived: false)
file_server = if archived
archive_root
else
student_work_root
end

"#{file_server}/portfolio/" # trust the server config and passed in type for paths
end

def unit_portfolio_dir(unit, create = true)
dst = root_portfolio_dir
def unit_portfolio_dir(unit, create: true, archived: true)
dst = if (unit.archived && archived) || (archived == :force)
"#{archive_root}/portfolio/"
else
"#{student_work_root}/portfolio/"
end

dst << sanitized_path("#{unit.code}-#{unit.id}") << '/'

Expand All @@ -243,8 +277,8 @@ def unit_portfolio_dir(unit, create = true)
#
# Generates a path for storing student portfolios
#
def student_portfolio_dir(unit, username, create = true)
dst = unit_portfolio_dir(unit, create)
def student_portfolio_dir(unit, username, create: true, archived: true)
dst = unit_portfolio_dir(unit, create: create, archived: archived)

dst << sanitized_path(username.to_s)

Expand All @@ -253,8 +287,8 @@ def student_portfolio_dir(unit, username, create = true)
dst
end

def student_portfolio_path(unit, username, create = true)
File.join(student_portfolio_dir(unit, username, create), FileHelper.sanitized_filename("#{username}-portfolio.pdf"))
def student_portfolio_path(unit, username, create: true, archived: true)
File.join(student_portfolio_dir(unit, username, create: create, archived: archived), FileHelper.sanitized_filename("#{username}-portfolio.pdf"))
end

def comment_attachment_path(task_comment, attachment_extension)
Expand Down Expand Up @@ -679,10 +713,13 @@ def line_wrap(path, width: 160)
module_function :student_group_work_dir
module_function :student_work_dir
module_function :student_work_root
module_function :archive_root
module_function :dir_for_unit_code_and_id
module_function :unit_dir
module_function :root_portfolio_dir
module_function :unit_portfolio_dir
module_function :unit_work_root
module_function :project_work_root
module_function :student_portfolio_dir
module_function :student_portfolio_path
module_function :comment_attachment_path
Expand Down
12 changes: 7 additions & 5 deletions app/mailers/d2l_result_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
class D2lResultMailer < ApplicationMailer
def result_message(unit, user)
def result_message(unit, user, result_message: 'completed', success: true)
email = user.email
return nil if email.blank?

path = D2lIntegration.result_file_path(unit)

if File.exist?(path)
attachments['result.csv'] = File.read(path)
end

@doubtfire_product_name = Doubtfire::Application.config.institution[:product_name]
@user = user
@unit = unit
@result_message = result_message
@has_file = success && File.exist?(path)

if @has_file
attachments['result.csv'] = File.read(path)
end

mail(to: email, from: email, subject: "#{@doubtfire_product_name} #{unit.code} - D2L Grade Transfer Result")
end
Expand Down
7 changes: 3 additions & 4 deletions app/models/group_submission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ class GroupSubmission < ApplicationRecord
FileHelper.delete_group_submission(group_submission)

# also remove evidence from group members
tasks.each do |t|
t.portfolio_evidence_path = nil
t.save
end
# rubocop:disable Rails/SkipsModelValidations
tasks.where('portfolio_evidence IS NOT NULL').update_all(portfolio_evidence: nil)
# rubocop:enable Rails/SkipsModelValidations
rescue => e
logger.error "Failed to delete group submission #{group_submission.id}. Error: #{e.message}"
end
Expand Down
6 changes: 3 additions & 3 deletions app/models/pdf_generation/project_compile_portfolio_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ def learning_summary_report_exists?
# Portfolio production code
#
def portfolio_temp_path
portfolio_dir = FileHelper.student_portfolio_dir(self.unit, self.student.username, false)
portfolio_tmp_dir = File.join(portfolio_dir, 'tmp')
portfolio_dir = FileHelper.student_portfolio_dir(self.unit, self.student.username, create: false)
File.join(portfolio_dir, 'tmp')
end

def portfolio_tmp_file_name(dict)
Expand Down Expand Up @@ -270,7 +270,7 @@ def remove_portfolio_file(idx, kind, name)
end

def portfolio_path
FileHelper.student_portfolio_path(self.unit, self.student.username, true)
FileHelper.student_portfolio_path(self.unit, self.student.username, create: true)
end

def portfolio_exists?
Expand Down
Loading