| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| app/controllers/submissions_controller.rb | 493 | 407 | 55.17%
|
50.12%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 require 'fastercsv' |
2 |
3 class SubmissionsController < ApplicationController |
4 include SubmissionsHelper |
5 include PaginationHelper |
6 |
7 before_filter :authorize_only_for_admin, :except => [:populate_file_manager, :browse, |
8 :index, :file_manager, :update_files, |
9 :download, :s_table_paginate, :collect_and_begin_grading, |
10 :manually_collect_and_begin_grading, :repo_browser, :populate_repo_browser, :update_converted_pdfs] |
11 before_filter :authorize_for_ta_and_admin, :only => [:browse, :index, :s_table_paginate, :collect_and_begin_grading, |
12 :manually_collect_and_begin_grading, :repo_browser, :populate_repo_browser, :update_converted_pdfs] |
13 before_filter :authorize_for_student, :only => [:file_manager, :populate_file_manager, :update_files] |
14 before_filter :authorize_for_user, :only => [:download] |
15 |
16 S_TABLE_PARAMS = { |
17 :model => Grouping, |
18 :per_pages => [15, 30, 50, 100, 150, 500, 1000], |
19 :filters => { |
20 'none' => { |
21 :display => I18n.t("browse_submissions.show_all"), |
22 :proc => lambda { |params, to_include| |
23 return params[:assignment].groupings.all(:include => to_include)}}, |
24 'unmarked' => { |
25 :display => I18n.t("browse_submissions.show_unmarked"), |
26 :proc => lambda { |params, to_include| return params[:assignment].groupings.all(:include => [to_include]).select{|g| !g.has_submission? || (g.has_submission? && g.current_submission_used.result.marking_state == Result::MARKING_STATES[:unmarked]) } }}, |
27 'partial' => { |
28 :display => I18n.t("browse_submissions.show_partial"), |
29 :proc => lambda { |params, to_include| return params[:assignment].groupings.all(:include => [to_include]).select{|g| g.has_submission? && g.current_submission_used.result.marking_state == Result::MARKING_STATES[:partial] } }}, |
30 'complete' => { |
31 :display => I18n.t("browse_submissions.show_complete"), |
32 :proc => lambda { |params, to_include| return params[:assignment].groupings.all(:include => [to_include]).select{|g| g.has_submission? && g.current_submission_used.result.marking_state == Result::MARKING_STATES[:complete] } }}, |
33 'released' => { |
34 :display => I18n.t("browse_submissions.show_released"), |
35 :proc => lambda { |params, to_include| return params[:assignment].groupings.all(:include => [to_include]).select{|g| g.has_submission? && g.current_submission_used.result.released_to_students} }}, |
36 'assigned' => { |
37 :display => I18n.t("browse_submissions.show_assigned_to_me"), |
38 :proc => lambda { |params, to_include| return params[:assignment].ta_memberships.find_all_by_user_id(params[:user_id], :include => [:grouping => to_include]).collect{|m| m.grouping} }} |
39 }, |
40 :sorts => { |
41 'group_name' => lambda { |a,b| a.group.group_name.downcase <=> b.group.group_name.downcase}, |
42 'repo_name' => lambda { |a,b| a.group.repo_name.downcase <=> b.group.repo_name.downcase }, |
43 'revision_timestamp' => lambda { |a,b| |
44 return -1 if !a.has_submission? |
45 return 1 if !b.has_submission? |
46 return a.current_submission_used.revision_timestamp <=> b.current_submission_used.revision_timestamp |
47 }, |
48 'marking_state' => lambda { |a,b| |
49 return -1 if !a.has_submission? |
50 return 1 if !b.has_submission? |
51 return a.current_submission_used.result.marking_state <=> b.current_submission_used.result.marking_state |
52 }, |
53 'total_mark' => lambda { |a,b| |
54 return -1 if !a.has_submission? |
55 return 1 if !b.has_submission? |
56 return a.current_submission_used.result.total_mark <=> b.current_submission_used.result.total_mark |
57 }, |
58 'grace_credits_used' => lambda { |a,b| |
59 return a.grace_period_deduction_sum <=> b.grace_period_deduction_sum |
60 } |
61 } |
62 } |
63 |
64 def repo_browser |
65 @grouping = Grouping.find(params[:id]) |
66 @assignment = @grouping.assignment |
67 @path = params[:path] || '/' |
68 @previous_path = File.split(@path).first |
69 @repository_name = @grouping.group.repository_name |
70 repo = @grouping.group.repo |
71 begin |
72 if !params[:revision_timestamp].nil? |
73 @revision_number = repo.get_revision_by_timestamp(Time.parse(params[:revision_timestamp])).revision_number |
74 elsif !params[:revision_number].nil? |
75 @revision_number = params[:revision_number].to_i |
76 else |
77 @revision_number = repo.get_latest_revision.revision_number |
78 end |
79 @revision = repo.get_revision(@revision_number) |
80 @revision_timestamp = @revision.timestamp |
81 repo.close |
82 rescue Exception => e |
83 flash[:error] = e.message |
84 @revision_number = repo.get_latest_revision.revision_number |
85 @revision_timestamp = repo.get_latest_revision.timestamp |
86 repo.close |
87 end |
88 end |
89 |
90 def populate_repo_browser |
91 @grouping = Grouping.find(params[:id]) |
92 @assignment = @grouping.assignment |
93 @path = params[:path] || '/' |
94 @revision_number = params[:revision_number] |
95 @previous_path = File.split(@path).first |
96 @grouping.group.access_repo do |repo| |
97 begin |
98 @revision = repo.get_revision(params[:revision_number].to_i) |
99 @directories = @revision.directories_at_path(File.join(@assignment.repository_folder, @path)) |
100 @files = @revision.files_at_path(File.join(@assignment.repository_folder, @path)) |
101 rescue Exception => @find_revision_error |
102 render :action => 'repo_browser/find_revision_error' |
103 return |
104 end |
105 @table_rows = {} |
106 @files.sort.each do |file_name, file| |
107 @table_rows[file.id] = construct_repo_browser_table_row(file_name, file) |
108 end |
109 @directories.sort.each do |directory_name, directory| |
110 @table_rows[directory.id] = construct_repo_browser_directory_table_row(directory_name, directory) |
111 end |
112 render :action => 'repo_browser/populate_repo_browser' |
113 end |
114 end |
115 |
116 def file_manager |
117 @assignment = Assignment.find(params[:id]) |
118 |
119 @grouping = current_user.accepted_grouping_for(@assignment.id) |
120 |
121 if @grouping.nil? |
122 redirect_to :controller => 'assignments', :action => 'student_interface', :id => params[:id] |
123 return |
124 end |
125 |
126 user_group = @grouping.group |
127 @path = params[:path] || '/' |
128 |
129 user_group.access_repo do |repo| |
130 @revision = repo.get_latest_revision |
131 @files = @revision.files_at_path(File.join(@assignment.repository_folder, @path)) |
132 @missing_assignment_files = [] |
133 @assignment.assignment_files.each do |assignment_file| |
134 if !@revision.path_exists?(File.join(@assignment.repository_folder, |
135 assignment_file.filename)) |
136 @missing_assignment_files.push(assignment_file) |
137 end |
138 end |
139 end |
140 end |
141 |
142 def populate_file_manager |
143 @assignment = Assignment.find(params[:id]) |
144 @grouping = current_user.accepted_grouping_for(@assignment.id) |
145 user_group = @grouping.group |
146 revision_number= params[:revision_number] |
147 @path = params[:path] || '/' |
148 @previous_path = File.split(@path).first |
149 |
150 user_group.access_repo do |repo| |
151 if revision_number.nil? |
152 @revision = repo.get_latest_revision |
153 else |
154 @revision = repo.get_revision(revision_number.to_i) |
155 end |
156 @directories = @revision.directories_at_path(File.join(@assignment.repository_folder, @path)) |
157 @files = @revision.files_at_path(File.join(@assignment.repository_folder, @path)) |
158 @table_rows = {} |
159 @files.sort.each do |file_name, file| |
160 @table_rows[file.id] = construct_file_manager_table_row(file_name, file) |
161 end |
162 if @grouping.repository_external_commits_only? |
163 @directories.sort.each do |directory_name, directory| |
164 @table_rows[directory.id] = construct_file_manager_dir_table_row(directory_name, directory) |
165 end |
166 end |
167 render :action => 'file_manager_populate' |
168 end |
169 end |
170 |
171 def manually_collect_and_begin_grading |
172 @grouping = Grouping.find(params[:id]) |
173 @revision_number = params[:current_revision_number].to_i |
174 SubmissionCollector.instance.manually_collect_submission(@grouping, |
175 @revision_number) |
176 redirect_to :action => 'update_converted_pdfs', :id => @grouping.id |
177 end |
178 |
179 def collect_and_begin_grading |
180 assignment = Assignment.find(params[:id]) |
181 grouping = Grouping.find(params[:grouping_id]) |
182 if !assignment.submission_rule.can_collect_now? |
183 flash[:error] = I18n.t("browse_submissions.could_not_collect", |
184 :group_name => grouping.group.group_name) |
185 else |
186 #Push grouping to the priority queue |
187 SubmissionCollector.instance.push_grouping_to_priority_queue(grouping) |
188 flash[:success] = I18n.t("collect_submissions.priority_given") |
189 end |
190 redirect_to :action => 'browse', :id => assignment.id |
191 end |
192 |
193 def collect_all_submissions |
194 assignment = Assignment.find(params[:id], :include => [:groupings]) |
195 if !assignment.submission_rule.can_collect_now? |
196 flash[:error] = I18n.t("collect_submissions.could_not_collect", |
197 :assignment_identifier => assignment.short_identifier) |
198 else |
199 submission_collector = SubmissionCollector.instance |
200 submission_collector.push_groupings_to_queue(assignment.groupings) |
201 flash[:success] = I18n.t("collect_submissions.collection_job_started", |
202 :assignment_identifier => assignment.short_identifier) |
203 end |
204 redirect_to :action => 'browse', :id => assignment.id |
205 end |
206 |
207 def update_converted_pdfs |
208 @grouping = Grouping.find(params[:id]) |
209 @submission = @grouping.current_submission_used |
210 @pdf_count= 0 |
211 @converted_count = 0 |
212 @submission.submission_files.each do |file| |
213 if file.is_pdf? |
214 @pdf_count += 1 |
215 if file.is_converted |
216 @converted_count += 1 |
217 end |
218 end |
219 end |
220 end |
221 |
222 def browse |
223 if current_user.ta? |
224 params[:filter] = 'assigned' |
225 else |
226 if params[:filter] == nil or params[:filter].blank? |
227 params[:filter] = 'none' |
228 end |
229 end |
230 if params[:sort_by] == nil or params[:sort_by].blank? |
231 params[:sort_by] = 'group_name' |
232 end |
233 @assignment = Assignment.find(params[:id]) |
234 @groupings, @groupings_total = handle_paginate_event( |
235 S_TABLE_PARAMS, # the data structure to handle filtering and sorting |
236 { :assignment => @assignment, # the assignment to filter by |
237 :user_id => current_user.id}, # the submissions accessable by the current user |
238 params) # additional parameters that affect things like sorting |
239 |
240 #Eager load all data only for those groupings that will be displayed |
241 sorted_groupings = @groupings |
242 @groupings = Grouping.find(:all, :conditions => {:id => sorted_groupings}, |
243 :include => [:assignment, :group, :grace_period_deductions, |
244 {:current_submission_used => :result}, |
245 {:accepted_student_memberships => :user}]) |
246 |
247 #re-sort @groupings by the previous order, because eager loading query |
248 #messed up the grouping order |
249 @groupings = sorted_groupings.map do |sorted_grouping| |
250 @groupings.detect do |unsorted_grouping| |
251 unsorted_grouping == sorted_grouping |
252 end |
253 end |
254 |
255 @current_page = params[:page].to_i() |
256 @per_page = params[:per_page] |
257 @filters = get_filters(S_TABLE_PARAMS) |
258 @per_pages = S_TABLE_PARAMS[:per_pages] |
259 @desc = params[:desc] |
260 @filter = params[:filter] |
261 @sort_by = params[:sort_by] |
262 end |
263 |
264 def index |
265 @assignments = Assignment.all(:order => :id) |
266 render :action => 'index', :layout => 'sidebar' |
267 end |
268 |
269 # controller handles transactional submission of files |
270 def update_files |
271 assignment_id = params[:id] |
272 assignment = Assignment.find(assignment_id) |
273 path = params[:path] || '/' |
274 grouping = current_user.accepted_grouping_for(assignment_id) |
275 if grouping.repository_external_commits_only? |
276 raise I18n.t("student.submission.external_submit_only") |
277 end |
278 if !grouping.is_valid? |
279 redirect_to :action => :file_manager, :id => assignment_id |
280 return |
281 end |
282 grouping.group.access_repo do |repo| |
283 |
284 assignment_folder = File.join(assignment.repository_folder, path) |
285 |
286 # Get the revision numbers for the files that we've seen - these |
287 # values will be the "expected revision numbers" that we'll provide |
288 # to the transaction to ensure that we don't overwrite a file that's |
289 # been revised since the user last saw it. |
290 file_revisions = params[:file_revisions].nil? ? [] : params[:file_revisions] |
291 |
292 # The files that will be replaced - just give an empty array |
293 # if params[:replace_files] is nil |
294 replace_files = params[:replace_files].nil? ? {} : params[:replace_files] |
295 |
296 # The files that will be deleted |
297 delete_files = params[:delete_files].nil? ? {} : params[:delete_files] |
298 |
299 # The files that will be added |
300 new_files = params[:new_files].nil? ? {} : params[:new_files] |
301 |
302 # Create transaction, setting the author. Timestamp is implicit. |
303 txn = repo.get_transaction(current_user.user_name) |
304 |
305 log_messages = [] |
306 begin |
307 # delete files marked for deletion |
308 delete_files.keys.each do |filename| |
309 txn.remove(File.join(assignment_folder, filename), file_revisions[filename]) |
310 log_messages.push(I18n.t("markus_logger.student_deleted_file", :user_name => current_user.user_name, :file_name => filename, :assignment => assignment.short_identifier)) |
311 end |
312 |
313 # Replace files |
314 replace_files.each do |filename, file_object| |
315 # Sometimes the file pointer of file_object is at the end of the file. |
316 # In order to avoid empty uploaded files, rewind it to be save. |
317 file_object.rewind |
318 txn.replace(File.join(assignment_folder, filename), file_object.read, file_object.content_type, file_revisions[filename]) |
319 log_messages.push(I18n.t("markus_logger.student_replaced_file", :user_name => current_user.user_name, :file_name => filename, :assignment => assignment.short_identifier)) |
320 end |
321 |
322 # Add new files |
323 new_files.each do |file_object| |
324 # sanitize_file_name in SubmissionsHelper |
325 if file_object.original_filename.nil? |
326 raise I18n.t("student.submission.invalid_file_name") |
327 end |
328 # Sometimes the file pointer of file_object is at the end of the file. |
329 # In order to avoid empty uploaded files, rewind it to be save. |
330 file_object.rewind |
331 txn.add(File.join(assignment_folder, sanitize_file_name(file_object.original_filename)), file_object.read, file_object.content_type) |
332 log_messages.push(I18n.t("markus_logger.student_submitted_file", :user_name => current_user.user_name, :file_name => file_object.original_filename, :assignment => assignment.short_identifier)) |
333 end |
334 |
335 # finish transaction |
336 if !txn.has_jobs? |
337 flash[:transaction_warning] = I18n.t("student.submission.no_action_detected") |
338 redirect_to :action => "file_manager", :id => assignment_id |
339 return |
340 end |
341 if !repo.commit(txn) |
342 flash[:update_conflicts] = txn.conflicts |
343 else |
344 flash[:success] = I18n.t('update_files.success') |
345 # flush log messages |
346 m_logger = MarkusLogger.instance |
347 log_messages.each do |msg| |
348 m_logger.log(msg) |
349 end |
350 end |
351 |
352 # Are we past collection time? |
353 if assignment.submission_rule.can_collect_now? |
354 flash[:commit_notice] = assignment.submission_rule.commit_after_collection_message(grouping) |
355 end |
356 redirect_to :action => "file_manager", :id => assignment_id |
357 |
358 rescue Exception => e |
359 raise e |
360 flash[:commit_error] = e.message |
361 redirect_to :action => "file_manager", :id => assignment_id |
362 end |
363 end |
364 end |
365 |
366 def download |
367 @assignment = Assignment.find(params[:id]) |
368 # find_appropriate_grouping can be found in SubmissionsHelper |
369 |
370 @grouping = find_appropriate_grouping(@assignment.id, params) |
371 |
372 revision_number = params[:revision_number] |
373 path = params[:path] || '/' |
374 @grouping.group.access_repo do |repo| |
375 if revision_number.nil? |
376 @revision = repo.get_latest_revision |
377 else |
378 @revision = repo.get_revision(revision_number.to_i) |
379 end |
380 |
381 begin |
382 file = @revision.files_at_path(File.join(@assignment.repository_folder, path))[params[:file_name]] |
383 file_contents = repo.download_as_string(file) |
384 rescue Exception => e |
385 render :text => I18n.t("student.submission.missing_file", :file_name => params[:file_name], :message => e.message) |
386 return |
387 end |
388 |
389 if SubmissionFile.is_binary?(file_contents) |
390 # If the file appears to be binary, send it as a download |
391 send_data file_contents, :disposition => 'attachment', :filename => params[:file_name] |
392 else |
393 # Otherwise, blast it out to the screen |
394 render :text => file_contents, :layout => 'sanitized_html' |
395 end |
396 end |
397 end |
398 |
399 def update_submissions |
400 return unless request.post? |
401 assignment = Assignment.find(params[:id]) |
402 errors = [] |
403 groupings = [] |
404 if params[:ap_select_full] == 'true' |
405 # We should have been passed a filter |
406 if params[:filter].blank? |
407 raise I18n.t("student.submission.expect_filter") |
408 end |
409 # Get all Groupings for this filter |
410 groupings = S_TABLE_PARAMS[:filters][params[:filter]][:proc].call({:assignment => assignment, :user_id => current_user.id}) |
411 else |
412 # User selected particular Grouping IDs |
413 if params[:groupings].nil? |
414 errors.push(I18n.t('results.must_select_a_group')) |
415 else |
416 groupings = assignment.groupings.find(params[:groupings]) |
417 end |
418 end |
419 |
420 log_message = "" |
421 if !params[:release_results].nil? |
422 changed = set_release_on_results(groupings, true, errors) |
423 log_message = I18n.t("markus_logger.marks_released_for_assignment", |
424 :assignment_id => assignment.id, |
425 :assignment => assignment.short_identifier, |
426 :number_groups => changed) |
427 elsif !params[:unrelease_results].nil? |
428 changed = set_release_on_results(groupings, false, errors) |
429 log_message = I18n.t("markus_logger.marks_unreleased_for_assignment", |
430 :assignment_id => assignment.id, |
431 :assignment => assignment.short_identifier, |
432 :number_groups => changed) |
433 end |
434 |
435 |
436 if !groupings.empty? |
437 assignment.set_results_average |
438 end |
439 |
440 if changed > 0 |
441 flash[:success] = I18n.t('results.successfully_changed', {:changed => changed}) |
442 m_logger = MarkusLogger.instance |
443 m_logger.log(log_message) |
444 end |
445 flash[:errors] = errors |
446 |
447 redirect_to :action => 'browse', :id => params[:id] |
448 end |
449 |
450 def unrelease |
451 return unless request.post? |
452 if params[:groupings].nil? |
453 flash[:release_results] = I18n.t("assignment.group.select_a_group") |
454 else |
455 params[:groupings].each do |g| |
456 g.unrelease_results |
457 end |
458 m_logger = MarkusLogger.instance |
459 assignment = Assignment.find(params[:id]) |
460 m_logger.log(I18n.t("markus_logger.marks_unreleased_for_assignment", |
461 :assignment_id => assignment.id, |
462 :assignment => assignment.short_identifier, |
463 :number_groups => params[:groupings].length)) |
464 end |
465 redirect_to :action => 'browse', :id => params[:id] |
466 end |
467 |
468 # See Assignment.get_simple_csv_report for details |
469 def download_simple_csv_report |
470 assignment = Assignment.find(params[:id]) |
471 send_data assignment.get_simple_csv_report, :disposition => 'attachment', :type => 'application/vnd.ms-excel', :filename => "#{assignment.short_identifier} simple report.csv" |
472 end |
473 |
474 # See Assignment.get_detailed_csv_report for details |
475 def download_detailed_csv_report |
476 assignment = Assignment.find(params[:id]) |
477 send_data assignment.get_detailed_csv_report, :disposition => 'attachment', :type => 'application/vnd.ms-excel', :filename => "#{assignment.short_identifier} detailed report.csv" |
478 end |
479 |
480 # See Assignment.get_svn_export_commands for details |
481 def download_svn_export_commands |
482 assignment = Assignment.find(params[:id]) |
483 svn_commands = assignment.get_svn_export_commands |
484 send_data svn_commands.join("\n"), :disposition => 'attachment', :type => 'text/plain', :filename => "#{assignment.short_identifier}_svn_exports" |
485 end |
486 |
487 # See Assignment.get_svn_repo_list for details |
488 def download_svn_repo_list |
489 assignment = Assignment.find(params[:id]) |
490 send_data assignment.get_svn_repo_list, :disposition => 'attachment', :type => 'text/plain', :filename => "#{assignment.short_identifier}_svn_repo_list" |
491 end |
492 |
493 end |
Generated on Thu Sep 09 00:10:34 -0400 2010 with rcov 0.9.8