Skip to content

Commit 5bae82b

Browse files
authored
Merge pull request #457 from macite/8.0.x
Add ability to auto archive units
2 parents 7e28e4b + 3d5b90c commit 5bae82b

26 files changed

+518
-112
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Doubtfire requires multiple environment variables that help define settings abou
3232
| `DF_AUTH_METHOD` | The authentication method you would like Doubtfire to use. Possible values are `database` for standard authentication with the database, `ldap` | `database` |
3333
| | 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). | |
3434
| `DF_STUDENT_WORK_DIR` | The directory to store uploaded student work for processing. | `student_work` |
35+
| `DF_ARCHIVE_DIR` | The directory to move archived unit files to, and access from. | `DF_STUDENT_WORK_DIR/archive` |
3536
| `DF_INSTITUTION_NAME` | The name of your institution running Doubtfire. | _University of Foo_ |
3637
| `DF_INSTITUTION_EMAIL_DOMAIN` | The email domain from which emails are sent to and from in your institution. | `doubtfire.com` |
3738
| `DF_INSTITUTION_HOST` | The host running the Doubtfire instance. | `localhost:3000` |

app/api/submission/portfolio_evidence_api.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ def self.logger
7676
optional :as_attachment, type: Boolean, desc: 'Whether or not to download file as attachment. Default is false.'
7777
end
7878
get '/projects/:id/task_def_id/:task_definition_id/submission' do
79-
project = Project.find(params[:id])
80-
task_definition = project.unit.task_definitions.find(params[:task_definition_id])
79+
project = Project.eager_load(:unit).find(params[:id])
80+
task_definition = project.unit.task_definitions.select(:id, :name, :abbreviation).find(params[:task_definition_id])
8181

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

8787
task = project.task_for_task_definition(task_definition)
8888

89-
evidence_loc = task.portfolio_evidence_path
90-
student = task.project.student
91-
unit = task.project.unit
89+
evidence_loc = task.final_pdf_path
9290

9391
if task.processing_pdf?
9492
evidence_loc = Rails.root.join('public/resources/AwaitingProcessing.pdf')
9593
filename = 'AwaitingProcessing.pdf'
96-
elsif evidence_loc.nil?
94+
elsif evidence_loc.nil? || !File.exist?(evidence_loc)
9795
evidence_loc = Rails.root.join('public/resources/FileNotFound.pdf')
9896
filename = 'FileNotFound.pdf'
9997
else

app/helpers/file_helper.rb

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,7 @@ def sanitized_filename(filename)
125125
end
126126

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

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

@@ -176,6 +174,30 @@ def student_work_root
176174
Doubtfire::Application.config.student_work_dir
177175
end
178176

177+
def archive_root
178+
Doubtfire::Application.config.archive_dir
179+
end
180+
181+
# Get the path to the unit root - will take into consideration if archived
182+
#
183+
# @param [Unit] unit - the unit to get the root path for
184+
# @param [Boolean] archived - whether to use the archived property (true/false)
185+
# or force it to be the archived path (:force)
186+
def unit_work_root(unit, archived: true)
187+
dst = if (unit.archived && archived) || (archived == :force)
188+
"#{archive_root}/"
189+
else
190+
"#{student_work_root}/"
191+
end
192+
193+
dst << sanitized_path("#{unit.code}-#{unit.id}") << '/'
194+
end
195+
196+
def project_work_root(project, archived: true, username: nil)
197+
username = project.student.username.to_s if username.nil?
198+
unit_work_root(project.unit, archived: archived) << sanitized_path(username) << '/'
199+
end
200+
179201
#
180202
# Generates a path for storing student work
181203
# type = [:new, :in_process, :done, :pdf, :plagarism]
@@ -187,18 +209,17 @@ def student_work_dir(type = nil, task = nil, create = true)
187209
file_server = Doubtfire::Application.config.student_work_dir
188210
dst = "#{file_server}/" # trust the server config and passed in type for paths
189211

190-
if !(type.nil? || task.nil?)
212+
if !(type.nil? || task.nil?) # we have task and type
191213
if [:discussion, :pdf, :comment].include? type
192-
dst << sanitized_path("#{task.project.unit.code}-#{task.project.unit.id}", task.project.student.username.to_s, type.to_s) << '/'
214+
dst = project_work_root(task.project) << sanitized_path(type.to_s) << '/'
193215
elsif [:done, :plagarism].include? type
194-
dst << sanitized_path("#{task.project.unit.code}-#{task.project.unit.id}", task.project.student.username.to_s, type.to_s, task.id.to_s) << '/'
216+
dst = project_work_root(task.project) << sanitized_path(type.to_s, task.id.to_s) << '/'
195217
else # new and in_process -- just have task id
196218
# Add task id to dst if we want task
197219
dst << "#{type}/#{task.id}/"
198220
end
199-
elsif !type.nil?
221+
elsif !type.nil? # have type but not task
200222
if [:in_process, :new].include? type
201-
# Add task id to dst if we want task
202223
dst << "#{type}/"
203224
else
204225
raise 'Error in request to student work directory'
@@ -211,27 +232,40 @@ def student_work_dir(type = nil, task = nil, create = true)
211232
dst
212233
end
213234

214-
def dir_for_unit_code_and_id(unit_code, unit_id, create = true)
215-
file_server = Doubtfire::Application.config.student_work_dir
216-
dst = "#{file_server}/" # trust the server config and passed in type for paths
235+
def dir_for_unit_code_and_id(unit_code, unit_id, create: true, archived: false)
236+
dst = if archived
237+
"#{archive_root}/"
238+
else
239+
"#{student_work_root}/"
240+
end
241+
217242
dst << sanitized_path("#{unit_code}-#{unit_id}")
218243

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

221246
dst
222247
end
223248

224-
def unit_dir(unit, create = true)
225-
dir_for_unit_code_and_id(unit.code, unit.id, create)
249+
def unit_dir(unit, create: true, archived: true)
250+
dir_for_unit_code_and_id(unit.code, unit.id, create: create, archived: archived == :force || (archived && unit.archived))
226251
end
227252

228-
def root_portfolio_dir
229-
file_server = Doubtfire::Application.config.student_work_dir
253+
def root_portfolio_dir(archived: false)
254+
file_server = if archived
255+
archive_root
256+
else
257+
student_work_root
258+
end
259+
230260
"#{file_server}/portfolio/" # trust the server config and passed in type for paths
231261
end
232262

233-
def unit_portfolio_dir(unit, create = true)
234-
dst = root_portfolio_dir
263+
def unit_portfolio_dir(unit, create: true, archived: true)
264+
dst = if (unit.archived && archived) || (archived == :force)
265+
"#{archive_root}/portfolio/"
266+
else
267+
"#{student_work_root}/portfolio/"
268+
end
235269

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

@@ -243,8 +277,8 @@ def unit_portfolio_dir(unit, create = true)
243277
#
244278
# Generates a path for storing student portfolios
245279
#
246-
def student_portfolio_dir(unit, username, create = true)
247-
dst = unit_portfolio_dir(unit, create)
280+
def student_portfolio_dir(unit, username, create: true, archived: true)
281+
dst = unit_portfolio_dir(unit, create: create, archived: archived)
248282

249283
dst << sanitized_path(username.to_s)
250284

@@ -253,8 +287,8 @@ def student_portfolio_dir(unit, username, create = true)
253287
dst
254288
end
255289

256-
def student_portfolio_path(unit, username, create = true)
257-
File.join(student_portfolio_dir(unit, username, create), FileHelper.sanitized_filename("#{username}-portfolio.pdf"))
290+
def student_portfolio_path(unit, username, create: true, archived: true)
291+
File.join(student_portfolio_dir(unit, username, create: create, archived: archived), FileHelper.sanitized_filename("#{username}-portfolio.pdf"))
258292
end
259293

260294
def comment_attachment_path(task_comment, attachment_extension)
@@ -679,10 +713,13 @@ def line_wrap(path, width: 160)
679713
module_function :student_group_work_dir
680714
module_function :student_work_dir
681715
module_function :student_work_root
716+
module_function :archive_root
682717
module_function :dir_for_unit_code_and_id
683718
module_function :unit_dir
684719
module_function :root_portfolio_dir
685720
module_function :unit_portfolio_dir
721+
module_function :unit_work_root
722+
module_function :project_work_root
686723
module_function :student_portfolio_dir
687724
module_function :student_portfolio_path
688725
module_function :comment_attachment_path

app/mailers/d2l_result_mailer.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
class D2lResultMailer < ApplicationMailer
2-
def result_message(unit, user)
2+
def result_message(unit, user, result_message: 'completed', success: true)
33
email = user.email
44
return nil if email.blank?
55

66
path = D2lIntegration.result_file_path(unit)
77

8-
if File.exist?(path)
9-
attachments['result.csv'] = File.read(path)
10-
end
11-
128
@doubtfire_product_name = Doubtfire::Application.config.institution[:product_name]
139
@user = user
1410
@unit = unit
11+
@result_message = result_message
12+
@has_file = success && File.exist?(path)
13+
14+
if @has_file
15+
attachments['result.csv'] = File.read(path)
16+
end
1517

1618
mail(to: email, from: email, subject: "#{@doubtfire_product_name} #{unit.code} - D2L Grade Transfer Result")
1719
end

app/models/group_submission.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ class GroupSubmission < ApplicationRecord
1818
FileHelper.delete_group_submission(group_submission)
1919

2020
# also remove evidence from group members
21-
tasks.each do |t|
22-
t.portfolio_evidence_path = nil
23-
t.save
24-
end
21+
# rubocop:disable Rails/SkipsModelValidations
22+
tasks.where('portfolio_evidence IS NOT NULL').update_all(portfolio_evidence: nil)
23+
# rubocop:enable Rails/SkipsModelValidations
2524
rescue => e
2625
logger.error "Failed to delete group submission #{group_submission.id}. Error: #{e.message}"
2726
end

app/models/pdf_generation/project_compile_portfolio_module.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,8 @@ def learning_summary_report_exists?
177177
# Portfolio production code
178178
#
179179
def portfolio_temp_path
180-
portfolio_dir = FileHelper.student_portfolio_dir(self.unit, self.student.username, false)
181-
portfolio_tmp_dir = File.join(portfolio_dir, 'tmp')
180+
portfolio_dir = FileHelper.student_portfolio_dir(self.unit, self.student.username, create: false)
181+
File.join(portfolio_dir, 'tmp')
182182
end
183183

184184
def portfolio_tmp_file_name(dict)
@@ -270,7 +270,7 @@ def remove_portfolio_file(idx, kind, name)
270270
end
271271

272272
def portfolio_path
273-
FileHelper.student_portfolio_path(self.unit, self.student.username, true)
273+
FileHelper.student_portfolio_path(self.unit, self.student.username, create: true)
274274
end
275275

276276
def portfolio_exists?

0 commit comments

Comments
 (0)