Rcov C0 Coverage Information - RCov

app/controllers/assignments_controller.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
app/controllers/assignments_controller.rb 495 401
70.71%
65.09%

Key

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.

Coverage Details

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