| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| app/controllers/assignments_controller.rb | 495 | 401 | 70.71%
|
65.09%
|
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 class AssignmentsController < ApplicationController |
3 before_filter :authorize_only_for_admin, |
4 :except => [:deletegroup, |
5 :delete_rejected, |
6 :disinvite_member, |
7 :invite_member, |
8 :creategroup, |
9 :join_group, |
10 :decline_invitation, |
11 :index, |
12 :student_interface, |
13 :update_collected_submissions] |
14 |
15 before_filter :authorize_for_student, |
16 :only => [:student_interface, |
17 :deletegroup, |
18 :delete_rejected, |
19 :disinvite_member, |
20 :invite_member, |
21 :creategroup, |
22 :join_group, |
23 :decline_invitation] |
24 |
25 before_filter :authorize_for_user, |
26 :only => [:index] |
27 |
28 auto_complete_for :assignment, |
29 :name |
30 # Publicly accessible actions --------------------------------------- |
31 |
32 def student_interface |
33 @assignment = Assignment.find(params[:id]) |
34 @student = current_user |
35 @grouping = @student.accepted_grouping_for(@assignment.id) |
36 if @student.has_pending_groupings_for?(@assignment.id) |
37 @pending_grouping = @student.pending_groupings_for(@assignment.id) |
38 end |
39 if @grouping.nil? |
40 if @assignment.group_max == 1 |
41 @student.create_group_for_working_alone_student(@assignment.id) |
42 redirect_to :action => 'student_interface', :id => @assignment.id |
43 else |
44 render :action => 'student_interface', :layout => 'no_menu_header' |
45 return |
46 end |
47 else |
48 # We look for the information on this group... |
49 # The members |
50 @studentmemberships = @grouping.student_memberships |
51 # The group name |
52 @group = @grouping.group |
53 # The inviter |
54 @inviter = @grouping.inviter |
55 |
56 # Look up submission information |
57 repo = @grouping.group.repo |
58 @revision = repo.get_latest_revision |
59 @revision_number = @revision.revision_number |
60 |
61 # For running tests |
62 if params[:collect] |
63 @result = manually_collect_and_prepare_test(@grouping, @revision.revision_number) |
64 else |
65 @result = automatically_collect_and_prepare_test(@grouping, @revision.revision_number) |
66 end |
67 #submission = @grouping.submissions.find_by_submission_version_used(true) |
68 if @result |
69 @test_result_files = @result.submission.test_results |
70 else |
71 @test_result_files = nil |
72 end |
73 @token = Token.find_by_grouping_id(@grouping.id) |
74 |
75 @last_modified_date = @grouping.assignment_folder_last_modified_date |
76 @num_submitted_files = @grouping.number_of_submitted_files |
77 @num_missing_assignment_files = @grouping.missing_assignment_files.length |
78 repo.close |
79 end |
80 end |
81 |
82 # Displays "Manage Assignments" page for creating and editing |
83 # assignment information |
84 def index |
85 @assignments = Assignment.all(:order => :id) |
86 @grade_entry_forms = GradeEntryForm.all(:order => :id) |
87 if current_user.student? |
88 # get results for assignments for the current user |
89 @a_id_results = Hash.new() |
90 @assignments.each do |a| |
91 if current_user.has_accepted_grouping_for?(a) |
92 grouping = current_user.accepted_grouping_for(a) |
93 if grouping.has_submission? |
94 submission = grouping.current_submission_used |
95 if submission.has_result? && submission.result.released_to_students |
96 @a_id_results[a.id] = submission.result |
97 end |
98 end |
99 end |
100 end |
101 |
102 # Get the grades for grade entry forms for the current user |
103 @g_id_entries = Hash.new() |
104 @grade_entry_forms.each do |g| |
105 grade_entry_student = g.grade_entry_students.find_by_user_id( |
106 current_user.id ) |
107 if !grade_entry_student.nil? && |
108 grade_entry_student.released_to_student |
109 @g_id_entries[g.id] = grade_entry_student |
110 end |
111 end |
112 |
113 render :action => "student_assignment_list" |
114 return |
115 elsif current_user.ta? |
116 render :action => "grader_index" |
117 else |
118 render :action => 'index' |
119 end |
120 end |
121 |
122 def edit |
123 @assignment = Assignment.find_by_id(params[:id]) |
124 if !params[:assignment].nil? |
125 @oldcriteria = @assignment.marking_scheme_type |
126 @newcriteria = params[:assignment][:marking_scheme_type] |
127 if @oldcriteria != @newcriteria and !@assignment.get_criteria.nil? |
128 #TODO use @assignment.criteria.destroy_all when the refactor of |
129 # criteria structure finished |
130 @assignment.get_criteria.each do |criterion| |
131 criterion.destroy |
132 end |
133 end |
134 end |
135 @assignments = Assignment.all |
136 if !request.post? |
137 return |
138 end |
139 |
140 begin |
141 @assignment = process_assignment_form(@assignment, params) |
142 rescue Exception, RuntimeError => e |
143 @assignment.errors.add_to_base(I18n.t("assignment.error", |
144 :message => e.message)) |
145 return |
146 end |
147 |
148 if @assignment.save |
149 flash[:success] = I18n.t("assignment.update_success") |
150 redirect_to :action => 'edit', :id => params[:id] |
151 return |
152 else |
153 render :action => 'edit' |
154 end |
155 end |
156 |
157 |
158 # Form accessible actions -------------------------------------------- |
159 # Post actions that we expect only forms to access them |
160 |
161 # Called when form for creating a new assignment is submitted |
162 def new |
163 @assignments = Assignment.all |
164 @assignment = Assignment.new |
165 @assignment.build_submission_rule |
166 |
167 if !request.post? |
168 # set default value if web submits are allowed |
169 @assignment.allow_web_submits = |
170 !MarkusConfigurator.markus_config_repository_external_submits_only? |
171 render :action => 'new' |
172 return |
173 end |
174 |
175 @assignment.transaction do |
176 begin |
177 @assignment = process_assignment_form(@assignment, params) |
178 rescue Exception, RuntimeError => e |
179 @assignment.errors.add_to_base(e.message) |
180 end |
181 if !@assignment.save |
182 render :action => :new |
183 return |
184 end |
185 if params[:persist_groups_assignment] |
186 @assignment.clone_groupings_from(params[:persist_groups_assignment]) |
187 end |
188 if @assignment.save |
189 flash[:success] = I18n.t("assignment.create_success") |
190 end |
191 end |
192 |
193 redirect_to :action => "edit", :id => @assignment.id |
194 end |
195 |
196 def update_group_properties_on_persist |
197 @assignment = Assignment.find(params[:assignment_id]) |
198 end |
199 |
200 def download_csv_grades_report |
201 assignments = Assignment.all(:order => 'id') |
202 students = Student.all |
203 csv_string = FasterCSV.generate do |csv| |
204 students.each do |student| |
205 row = [] |
206 row.push(student.user_name) |
207 assignments.each do |assignment| |
208 out_of = assignment.total_mark |
209 grouping = student.accepted_grouping_for(assignment.id) |
210 if grouping.nil? |
211 row.push('') |
212 else |
213 submission = grouping.current_submission_used |
214 if submission.nil? |
215 row.push('') |
216 else |
217 total_mark_percentage = submission.result.total_mark / out_of * 100 |
218 if total_mark_percentage.nan? |
219 row.push('') |
220 else |
221 row.push(total_mark_percentage) |
222 end |
223 end |
224 end |
225 end |
226 csv << row |
227 end |
228 end |
229 send_data csv_string, :disposition => "attachment", |
230 :filename => "#{COURSE_NAME} grades report.csv" |
231 end |
232 |
233 |
234 # Methods for the student interface |
235 |
236 def join_group |
237 @assignment = Assignment.find(params[:id]) |
238 @grouping = Grouping.find(params[:grouping_id]) |
239 @user = Student.find(session[:uid]) |
240 @user.join(@grouping.id) |
241 m_logger = MarkusLogger.instance |
242 m_logger.log(I18n.t("markus_logger.student_accepted_invitation", |
243 :user_name => @user.user_name, |
244 :group => @grouping.group.group_name)) |
245 redirect_to :action => 'student_interface', :id => params[:id] |
246 end |
247 |
248 def decline_invitation |
249 @assignment = Assignment.find(params[:id]) |
250 @grouping = Grouping.find(params[:grouping_id]) |
251 @user = Student.find(session[:uid]) |
252 @grouping.decline_invitation(@user) |
253 m_logger = MarkusLogger.instance |
254 m_logger.log(I18n.t("markus_logger.student_declined_invitation", |
255 :user_name => @user.user_name, |
256 :group => @grouping.group.group_name)) |
257 redirect_to :action => 'student_interface', :id => params[:id] |
258 end |
259 |
260 def creategroup |
261 @assignment = Assignment.find(params[:id]) |
262 @student = @current_user |
263 m_logger = MarkusLogger.instance |
264 |
265 begin |
266 # We do not allow group creations by students after the due date |
267 # and the grace period for an assignment |
268 if @assignment.past_collection_date? |
269 raise I18n.t('create_group.fail.due_date_passed') |
270 end |
271 if !@assignment.student_form_groups || |
272 @assignment.instructor_form_groups |
273 raise I18n.t('create_group.fail.not_allow_to_form_groups') |
274 end |
275 if @student.has_accepted_grouping_for?(@assignment.id) |
276 raise I18n.t('create_group.fail.already_have_a_group') |
277 end |
278 if params[:workalone] |
279 if @assignment.group_min != 1 |
280 raise I18n.t('create_group.fail.can_not_work_alone', |
281 :group_min => @assignment.group_min) |
282 end |
283 @student.create_group_for_working_alone_student(@assignment.id) |
284 else |
285 @student.create_autogenerated_name_group(@assignment.id) |
286 end |
287 m_logger.log(I18n.t("markus_logger.student_created_group", |
288 :user_name => @student.user_name), |
289 MarkusLogger::INFO) |
290 rescue RuntimeError => e |
291 flash[:fail_notice] = e.message |
292 m_logger.log(I18n.t("markus_logger.student_create_group_fail", |
293 :user_name => @student.user_name, |
294 :error => e.message), |
295 MarkusLogger::ERROR) |
296 end |
297 redirect_to :action => 'student_interface', :id => @assignment.id |
298 end |
299 |
300 def deletegroup |
301 @assignment = Assignment.find(params[:id]) |
302 @grouping = @current_user.accepted_grouping_for(@assignment.id) |
303 m_logger = MarkusLogger.instance |
304 begin |
305 if @grouping.nil? |
306 raise I18n.t('create_group.fail.do_not_have_a_group') |
307 end |
308 # If grouping is not deletable for @current_user for whatever reason, fail. |
309 if !@grouping.deletable_by?(@current_user) |
310 raise I18n.t('groups.cant_delete') |
311 end |
312 if @grouping.has_submission? |
313 raise I18n.t('groups.cant_delete_already_submitted') |
314 end |
315 @grouping.student_memberships.all(:include => :user).each do |member| |
316 member.destroy |
317 end |
318 # update repository permissions |
319 @grouping.update_repository_permissions |
320 @grouping.destroy |
321 flash[:edit_notice] = I18n.t('assignment.group.deleted') |
322 m_logger.log(I18n.t("markus_logger.student_deleted_group", |
323 :user_name => current_user.user_name, |
324 :group => @grouping.group.group_name), |
325 MarkusLogger::INFO) |
326 |
327 rescue RuntimeError => e |
328 flash[:fail_notice] = e.message |
329 if @grouping.nil? |
330 m_logger.log( |
331 I18n.t("markus_logger.student_delete_group_fail_no_grouping", |
332 :user_name => current_user.user_name, |
333 :error => e.message), |
334 MarkusLogger::ERROR) |
335 else |
336 m_logger.log(I18n.t("markus_logger.student_delete_group_fail", |
337 :user_name => current_user.user_name, |
338 :group => @grouping.group.group_name, |
339 :error => e.message), |
340 MarkusLogger::ERROR) |
341 end |
342 end |
343 redirect_to :action => 'student_interface', :id => params[:id] |
344 end |
345 |
346 def invite_member |
347 return unless request.post? |
348 @assignment = Assignment.find(params[:id]) |
349 # if instructor formed group return |
350 return if @assignment.instructor_form_groups |
351 |
352 @student = @current_user |
353 @grouping = @student.accepted_grouping_for(@assignment.id) |
354 if @grouping.nil? |
355 raise I18n.t('invite_student.fail.need_to_create_group') |
356 end |
357 |
358 to_invite = params[:invite_member].split(',') |
359 flash[:fail_notice] = [] |
360 flash[:success] = [] |
361 m_logger = MarkusLogger.instance |
362 @grouping.invite(to_invite) |
363 flash[:fail_notice] = @grouping.errors["base"] |
364 if flash[:fail_notice].blank? |
365 flash[:success] = I18n.t('invite_student.success') |
366 end |
367 redirect_to :action => 'student_interface', :id => @assignment.id |
368 end |
369 |
370 # Called by clicking the cancel link in the student's interface |
371 # i.e. cancels invitations |
372 def disinvite_member |
373 @assignment = Assignment.find(params[:id]) |
374 membership = StudentMembership.find(params[:membership]) |
375 disinvited_student = membership.user |
376 membership.delete |
377 membership.save |
378 # update repository permissions |
379 grouping = current_user.accepted_grouping_for(@assignment.id) |
380 grouping.update_repository_permissions |
381 m_logger = MarkusLogger.instance |
382 m_logger.log(I18n.t('markus_logger.student_cancelled_invitation', |
383 :inviter => current_user.user_name, |
384 :invitee => disinvited_student.user_name)) |
385 flash[:edit_notice] = I18n.t('student.member_disinvited') |
386 end |
387 |
388 # Deletes memberships which have been declined by students |
389 def delete_rejected |
390 @assignment = Assignment.find(params[:id]) |
391 membership = StudentMembership.find(params[:membership]) |
392 grouping = membership.grouping |
393 if current_user != grouping.inviter |
394 raise I18n.t('invite_student.fail.only_inviter') |
395 end |
396 membership.delete |
397 membership.save |
398 redirect_to :action => 'student_interface', :id => params[:id] |
399 end |
400 |
401 def update_collected_submissions |
402 @assignments = Assignment.all |
403 end |
404 |
405 private |
406 |
407 def process_assignment_form(assignment, params) |
408 assignment.attributes = params[:assignment] |
409 # Was the SubmissionRule changed? If so, wipe out any existing |
410 # Periods, and switch the type of the SubmissionRule. |
411 # This little conditional has to do some hack-y workarounds, since |
412 # accepts_nested_attributes_for is a little...dumb. |
413 if assignment.submission_rule.attributes['type'] != |
414 params[:assignment][:submission_rule_attributes][:type] |
415 # Some protective measures here to make sure we haven't been duped... |
416 potential_rule = |
417 Module.const_get(params[:assignment][:submission_rule_attributes][:type]) |
418 if !potential_rule.ancestors.include?(SubmissionRule) |
419 raise I18n.t("assignment.not_valid_submission_rule", |
420 :type => params[:assignment][:submission_rule_attributes][:type]) |
421 end |
422 |
423 assignment.submission_rule.destroy |
424 submission_rule = SubmissionRule.new |
425 # A little hack to get around Rails' protection of the "type" |
426 # attribute |
427 submission_rule.type = |
428 params[:assignment][:submission_rule_attributes][:type] |
429 assignment.submission_rule = submission_rule |
430 # For some reason, when we create new rule, we can't just apply |
431 # the params[:assignment] hash to @assignment.attributes...we have |
432 # to create any new periods manually, like this: |
433 if !params[:assignment][:submission_rule_attributes][:periods_attributes].nil? |
434 assignment.submission_rule.periods_attributes = |
435 params[:assignment][:submission_rule_attributes][:periods_attributes] |
436 end |
437 end |
438 |
439 if params[:is_group_assignment] == "true" |
440 # Is the instructor forming groups? |
441 if params[:assignment][:student_form_groups] == "0" |
442 assignment.instructor_form_groups = true |
443 else |
444 assignment.student_form_groups = true |
445 assignment.instructor_form_groups = false |
446 assignment.group_name_autogenerated = true |
447 end |
448 else |
449 assignment.student_form_groups = false; |
450 assignment.instructor_form_groups = false; |
451 assignment.group_min = 1; |
452 assignment.group_max = 1; |
453 end |
454 return assignment |
455 end |
456 |
457 def find_submission_for_test(grouping_id, revision_number) |
458 return Submission.find_by_grouping_id_and_revision_number(grouping_id, revision_number) |
459 end |
460 |
461 # Used every time a student access to the assignment page |
462 # It checks if the due date is passed, and if not, it |
463 # collect the last submission revision |
464 def automatically_collect_and_prepare_test(grouping, revision_number) |
465 # if there is no result for this grouping, |
466 # do nothing, because a student of the grouping |
467 # must run collec_and_test manually first |
468 return if grouping.submissions.empty? |
469 # Once it is time to collect files, student should'nt start to do tests |
470 if !grouping.assignment.submission_rule.can_collect_now? |
471 current_submission_used = grouping.submissions.find_by_submission_version_used(true) |
472 if current_submission_used.revision_number < revision_number |
473 new_submission = Submission.create_by_revision_number(grouping, revision_number) |
474 result = new_submission.result |
475 else |
476 result = current_submission_used.result |
477 end |
478 end |
479 return result |
480 end |
481 |
482 # Used the first time a student from a grouping wanted |
483 # to do test on his code |
484 def manually_collect_and_prepare_test(grouping, revision_number) |
485 # We check if it not the time to collect files |
486 # Once it is time to collect files, student should'nt start to do tests |
487 # And we create a submission with the latest revision of the svn |
488 if !grouping.assignment.submission_rule.can_collect_now? |
489 new_submission = Submission.create_by_revision_number(grouping, revision_number) |
490 result = new_submission.result |
491 end |
492 return result |
493 end |
494 |
495 end |
Generated on Wed Sep 08 00:10:29 -0400 2010 with rcov 0.9.8