Rcov C0 Coverage Information - RCov

app/controllers/groups_controller.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
app/controllers/groups_controller.rb 429 335
89.28%
86.87%

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 require 'auto_complete'
3 require 'csv_invalid_line_error'
4 
5 # Manages actions relating to editing and modifying
6 # groups.
7 class GroupsController < ApplicationController
8   include GroupsHelper
9   # Administrator
10   # -
11   before_filter      :authorize_only_for_admin
12 
13   auto_complete_for :student, :user_name
14   auto_complete_for :assignment, :name
15 
16   def note_message
17     @assignment = Assignment.find(params[:id])
18     if params[:success]
19       flash[:upload_notice] = I18n.t('notes.create.success')
20     else
21       flash[:error] = I18n.t('notes.error')
22     end
23   end
24 
25   # Group administration functions -----------------------------------------
26   # Verify that all functions below are included in the authorize filter above
27 
28   def new
29     @assignment = Assignment.find(params[:assignment_id])
30     begin
31       new_grouping_data = @assignment.add_group(params[:new_group_name])
32     rescue Exception => e
33       @error = e.message
34       render :action => 'error_single'
35       return
36     end
37     @new_grouping = construct_table_row(new_grouping_data, @assignment)
38     render :add_group
39   end
40 
41   def remove_group
42     return unless request.delete?
43     grouping = Grouping.find(params[:grouping_id])
44     @assignment = grouping.assignment
45     @errors = []
46     @removed_groupings = []
47     if grouping.has_submission?
48         @errors.push(grouping.group.group_name)
49         render :action => "delete_groupings"
50     else
51       grouping.delete_grouping
52       @removed_groupings.push(grouping)
53       render :action => "delete_groupings"
54     end
55   end
56 
57   def upload_dialog
58     @assignment = Assignment.find(params[:id])
59     render :partial => "groups/modal_dialogs/upload_dialog.rjs"
60   end
61 
62   def download_dialog
63     @assignment = Assignment.find(params[:id])
64     render :partial => "groups/modal_dialogs/download_dialog.rjs"
65   end
66 
67   def rename_group_dialog
68     @assignment = Assignment.find(params[:assignment_id])
69     @grouping_id = params[:grouping_id]
70     render :partial => "groups/modal_dialogs/rename_group_dialog.rjs"
71   end
72 
73   def rename_group
74     @assignment = Assignment.find(params[:assignment_id])
75     @grouping = Grouping.find(params[:grouping_id])
76     @group = @grouping.group
77 
78     # Checking if a group with this name already exists
79 
80     if (@groups = Group.find(:first, :conditions => {:group_name =>
81     [params[:new_groupname]]}))
82        existing = true
83        groupexist_id = @groups.id
84     end
85 
86     if !existing
87       #We update the group_name
88       @group.group_name = params[:new_groupname]
89       @group.save
90     else
91 
92       # We link the grouping to the group already existing
93 
94       # We verify there is no other grouping linked to this group on the
95       # same assignement
96       params[:groupexist_id] = groupexist_id
97       params[:assignment_id] = @assignment.id
98 
99       if Grouping.find(:all, :conditions => ["assignment_id =
100       :assignment_id and group_id = :groupexist_id", {:groupexist_id =>
101       groupexist_id, :assignment_id => @assignment.id}])
102          flash[:fail_notice] = I18n.t('groups.rename_group.already_in_use')
103       else
104         @grouping.update_attribute(:group_id, groupexist_id)
105       end
106     end
107     @grouping_data = construct_table_row(@grouping, @assignment)
108   end
109 
110   def valid_grouping
111     @assignment = Assignment.find(params[:assignment_id])
112     @grouping = Grouping.find(params[:grouping_id])
113     @grouping.validate_grouping
114     @grouping_data = construct_table_row(@grouping, @assignment)
115   end
116 
117   def invalid_grouping
118     @assignment = Assignment.find(params[:assignment_id])
119     @grouping = Grouping.find(params[:grouping_id])
120     @grouping.invalidate_grouping
121     @grouping_data = construct_table_row(@grouping, @assignment)
122   end
123 
124   def populate
125     @assignment = Assignment.find(params[:assignment_id],
126                                   :include => [{
127                                       :groupings => [
128                                           :students,
129                                           :non_rejected_student_memberships,
130                                           :group]}])
131     @groupings = @assignment.groupings
132     @table_rows = {}
133     @groupings.each do |grouping|
134       @table_rows[grouping.id] = construct_table_row(grouping, @assignment)
135     end
136   end
137 
138   def populate_students
139     @assignment = Assignment.find(params[:assignment_id],
140                                   :include => [:groupings])
141     @students = Student.find(:all)
142     @table_rows = construct_student_table_rows(@students, @assignment)
143   end
144 
145   def index
146     @all_assignments = Assignment.all(:order => :id)
147     @assignment = Assignment.find(params[:assignment_id])
148   end
149 
150   # Allows the user to upload a csv file listing groups. If group_name is equal
151   # to the only member of a group and the assignment is configured with
152   # allow_web_subits == false, the student's username will be used as the
153   # repository name. If MarkUs is not repository admin, the repository name as
154   # specified by the second field will be used instead.
155   def csv_upload
156     flash[:error] = nil # reset from previous errors
157     flash[:invalid_lines] = nil
158     @assignment = Assignment.find(params[:assignment_id])
159     if request.post? && !params[:group].blank?
160       # Transaction allows us to potentially roll back if something
161       # really bad happens.
162       ActiveRecord::Base.transaction do
163         # Old groupings get wiped out
164         if !@assignment.groupings.nil? && @assignment.groupings.length > 0
165           @assignment.groupings.destroy_all
166         end
167         flash[:invalid_lines] = [] # Store errors of lines in CSV file
168         begin
169           # Loop over each row, which lists the members to be added to the group.
170           FasterCSV.parse(params[:group][:grouplist].read).each_with_index do |row, line_nr|
171             begin
172               # Potentially raises CSVInvalidLineError
173               collision_error = @assignment.add_csv_group(row)
174               if !collision_error.nil?
175                 flash[:invalid_lines] << I18n.t("csv.line_nr_csv_file_prefix",
176                                           { :line_number => line_nr + 1 })
177                                           + " #{collision_error}"
178               end
179             rescue CSVInvalidLineError => e
180               flash[:invalid_lines] << I18n.t("csv.line_nr_csv_file_prefix",
181                                           { :line_number => line_nr + 1 })
182                                           + " #{e.message}"
183             end
184           end
185           @assignment.reload # Need to reload to get newly created groupings
186           number_groupings_added = @assignment.groupings.length
187           invalid_lines_count = flash[:invalid_lines].length
188           if invalid_lines_count == 0
189             flash[:invalid_lines] = nil
190           end
191           if number_groupings_added > 0
192             flash[:upload_notice] = I18n.t("csv.groups_added_msg",
193                   { :number_groups => number_groupings_added,
194                     :number_lines => invalid_lines_count })
195           end
196         rescue Exception => e
197           # We should only get here if something *really* bad/unexpected
198           # happened.
199           flash[:error] = I18n.t("csv.groups_unrecoverable_error")
200           raise ActiveRecord::Rollback
201         end
202       end
203       # Need to reestablish repository permissions.
204       # This is not handled by the roll back.
205       @assignment.update_repository_permissions_forall_groupings
206     end
207     redirect_to :action => "index", :id => params[:id]
208   end
209 
210   def download_grouplist
211     assignment = Assignment.find(params[:assignment_id])
212 
213     #get all the groups
214     groupings = assignment.groupings #FIXME: optimize with eager loading
215 
216     file_out = FasterCSV.generate do |csv|
217        groupings.each do |grouping|
218          group_array = [grouping.group.group_name, grouping.group.repo_name]
219          # csv format is group_name, repo_name, user1_name, user2_name, ... etc
220          grouping.student_memberships.all(:include => :user).each do |member|
221             group_array.push(member.user.user_name);
222          end
223          csv << group_array
224        end
225      end
226 
227     send_data(file_out, :type => "text/csv", :disposition => "inline")
228   end
229 
230   def use_another_assignment_groups
231     @target_assignment = Assignment.find(params[:assignment_id])
232     source_assignment = Assignment.find(params[:clone_groups_assignment_id])
233 
234     if source_assignment.nil?
235       flash[:fail_notice] = I18n.t("groups.csv.could_not_find_source")
236     end
237     if @target_assignment.nil?
238       flash[:fail_notice] = I18n.t("groups.csv.could_not_find_target")
239     end
240 
241     # Clone the groupings
242     @target_assignment.clone_groupings_from(source_assignment.id)
243   end
244 
245   #These actions act on all currently selected students & groups
246   def global_actions
247     @assignment = Assignment.find(params[:assignment_id],
248                                   :include => [{
249                                       :groupings => [{
250                                           :student_memberships => :user,
251                                           :ta_memberships => :user},
252                                         :group]}])
253     @tas = Ta.all
254     grouping_ids = params[:groupings]
255     student_ids = params[:students]
256 
257     if params[:groupings].nil? or params[:groupings].size ==  0
258       #Just do nothing
259       render :nothing => true
260       return
261     end
262 
263     @grouping_data = {}
264     @groupings = []
265     groupings = Grouping.find(grouping_ids)
266 
267     case params[:global_actions]
268       when "delete"
269         delete_groupings(groupings)
270         return
271       when "invalid"
272         invalidate_groupings(groupings)
273         return
274       when "valid"
275         validate_groupings(groupings)
276         return
277       when "assign"
278         if grouping_ids.length != 1
279           @error = I18n.t("assignment.group.select_only_one_group")
280           render :action => 'error_single'
281         elsif student_ids
282           add_members(student_ids, grouping_ids[0], @assignment)
283           return
284         else
285           render :nothing => true
286           return
287         end
288       when "unassign"
289         remove_members(groupings, params)
290         return
291     end
292   end
293 
294   private
295   #These methods are called through global actions
296 
297   # Given a list of grouping, sets their group status to invalid if possible
298   def invalidate_groupings(groupings)
299     groupings.each do |grouping|
300      grouping.invalidate_grouping
301     end
302     @groupings_data = construct_table_rows(groupings, @assignment)
303     render :action => "modify_groupings"
304   end
305 
306   # Given a list of grouping, sets their group status to valid if possible
307   def validate_groupings(groupings)
308     groupings.each do |grouping|
309       grouping.validate_grouping
310     end
311     @groupings_data = construct_table_rows(groupings, @assignment)
312     render :action => "modify_groupings"
313   end
314 
315   # Deletes the given list of groupings if possible
316   def delete_groupings(groupings)
317       @removed_groupings = []
318       @errors = []
319       groupings.each do |grouping|
320         if grouping.has_submission?
321           @errors.push(grouping.group.group_name)
322         else
323           grouping.delete_grouping
324           @removed_groupings.push(grouping)
325         end
326       end
327       render :action => "delete_groupings"
328   end
329 
330   # Adds the students given in student_ids to the grouping given in grouping_id
331   def add_members(student_ids, grouping_id, assignment)
332     students = Student.find(student_ids)
333     grouping = Grouping.find(grouping_id)
334     students.each do |student|
335       add_member(student, grouping, assignment)
336     end
337     @groupings_data = construct_table_rows([grouping], @assignment)
338     @students_data = construct_student_table_rows(students, @assignment)
339 
340     # Generate warning if the number of people assigned to a group exceeds
341     # the maximum size of a group
342     students_in_group = grouping.student_membership_number
343     group_name = grouping.group.group_name
344     if students_in_group > assignment.group_max
345       @warning = I18n.t("assignment.group.assign_over_limit",
346         :group => group_name)
347     end
348 
349     render :action => "add_members"
350     return
351   end
352 
353   # Adds the student given in student_id to the grouping given in grouping
354   def add_member  (student, grouping, assignment)
355     set_membership_status = grouping.student_memberships.empty? ?
356           StudentMembership::STATUSES[:inviter] :
357           StudentMembership::STATUSES[:accepted]
358     @messages = []
359     @bad_user_names = []
360     @error = false
361 
362     begin
363       if student.hidden
364         raise I18n.t('add_student.fail.hidden', student.user_name)
365       end
366       if student.has_accepted_grouping_for?(@assignment.id)
367         raise I18n.t('add_student.fail.already_grouped',
368           :user_name => student.user_name)
369       end
370       membership_count = grouping.student_memberships.length
371       grouping.invite(student.user_name, set_membership_status, true)
372       grouping.reload
373 
374       # report success only if # of memberships increased
375       if membership_count < grouping.student_memberships.length
376         @messages.push(I18n.t('add_student.success',
377             :user_name => student.user_name))
378       else # something clearly went wrong
379         raise I18n.t('add_student.fail.general',
380           :user_name => student.user_name)
381       end
382 
383       # only the first student should be the "inviter"
384       # (and only update this if it succeeded)
385       set_membership_status = StudentMembership::STATUSES[:accepted]
386     rescue Exception => e
387       @error = true
388       @messages.push(e.message)
389     end
390 
391     grouping.reload
392     @grouping = construct_table_row(grouping, assignment)
393     @group_name = grouping.group.group_name
394   end
395 
396   # Removes the students contained in params from the groupings given
397   # in groupings.
398   # This is meant to be called with the params from global_actions, and for
399   # each student to delete it will have a parameter
400   # of the form "groupid_studentid"
401   def remove_members(groupings, params)
402     all_members = []
403     groupings.each do |grouping|
404       members = grouping.students.delete_if do |student|
405                   !params["#{grouping.id}_#{student.user_name}"]
406                 end
407       memberships = members.map do |member|
408         grouping.student_memberships.find_by_user_id(member.id)
409       end
410       memberships.each do |membership|
411         remove_member(membership, grouping, @assignment)
412       end
413       all_members = all_members.concat(members)
414     end
415     @students_data = construct_student_table_rows(all_members, @assignment)
416     @groupings_data = construct_table_rows(groupings, @assignment)
417     render :action => "remove_members"
418   end
419 
420   #Removes the given student membership from the given grouping
421   def remove_member(membership, grouping, assignment)
422     @grouping = grouping
423     grouping.remove_member(membership.id)
424     grouping.reload
425     if !grouping.inviter.nil?
426       @inviter = grouping.accepted_student_memberships.find_by_user_id(grouping.inviter.id)
427     end
428   end
429 end

Generated on Tue Feb 07 00:07:35 -0500 2012 with rcov 0.9.10