CSC/ECE 517 Spring 2015/oss E1507 DG: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
(Created page with "=E1507. Refactoring Review Files Controller & Submitted Content Controller= This")
 
No edit summary
Line 1: Line 1:
=E1507. Refactoring Review Files Controller & Submitted Content Controller=
'''E1507. Refactoring Review Files Controller & Submitted Content Controller'''


This
This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the Review Files Controller & Submitted Content Controller as well as fixing the bug [https://github.com/expertiza/expertiza/issues/483 #483]
 
=What is Expertiza=
[http://http://expertiza.ncsu.edu/ Expertiza] is a [http://en.wikipedia.org/wiki/Open-source_software Open Source] [http://rubyonrails.org/ Rails] application where students can submit and peer-review learning objects (articles, code, web sites, etc). It is used in select courses at NC State and by professors at several other colleges and universities.  This Open Source application can be cloned from [https://github.com/expertiza/expertiza/ Github], the latest active branch is [https://github.com/expertiza/expertiza/tree/rails4 "Rails 4"].
 
=Project Desicription=
==Bug #483==
In "Your works" view, students can only submit links but no files.
 
[[File:Ossp1.png]]
 
This is caused by commit [https://github.com/expertiza/expertiza/commit/f313711fee2dd92e324603b9c506d9d5470c3b60 f313711] where the line 13 in [https://github.com/expertiza/expertiza/blob/f313711fee2dd92e324603b9c506d9d5470c3b60/app/views/submitted_content/_main.html.erb submitted_content/_main.html.erb] was commented out.
 
<%#= render partial: 'submitted_content/submitted_files', locals: {participant: @participant, stage: @stage} %>
 
But after uncommented line 13 in <code>submitted_content/_main.html.erb</code> and refresh the page, the Rails Server stopped responding.
 
==Refactoring Review Files Controller & Submitted Content Controller==
===What they do===
This [https://github.com/expertiza/expertiza/blob/rails4/app/controllers/review_files_controller.rb review_files_controller.rb] is responsible for handling the review files of the participants. This controller helps in uploading newer versions of reviews for an assignment and also in displaying all the versions (and diff between versions/code) with the help of [https://github.com/expertiza/expertiza/blob/rails4/app/controllers/submitted_content_controller.rb submitted_content_controller.rb].
===What’s wrong with them===
There are quite a few complex functions inside these controllers. These functions can easily be broken up into much more smaller methods with specific functionalities. They also need to be refactored to meet the [https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].
 
==What needs to be done==
1.Fix this bug #483
 
2.Break up the complex methods such as <code>get_comments</code>, <code>show_code_file_diff</code>. Anything that can be modularized should be modularized (Single Responsibility)
 
3.While breaking up the complex methods, look out for possible helper functions. If there are any, move them to the <code>review_files_helper.rb</code>
 
4.Remove commented out code from the controller
 
5.Refactor the file based on Global Rules provided at the top of this document
 
=Changes Made=
==For Bug #483 fixing==
Git log can be viewed in commit [https://github.com/KeleiAzz/expertiza/commit/aa37e2e61d0bf93a9bd0707621cd764017252f58 aa37e2e]
 
1. In <code>submitted_content_controller.rb</code>, line 19.
if @assignment.max_team_size > 1 && @participant.team.nil?
      flash[:error] = "This is a team assignment. Before submitting your work, you must <a style='color: blue;' href='../../student_teams/view/?student_id=#{params[:id]}'>create a team</a>,
                      even if you will be the only member of the team"
      redirect_to controller: 'student_task', action: 'view', id: params[:id]
else if @participant.team.nil?
      #create a new team for current user before submission
      team = AssignmentTeam.create_team_and_node(@assignment.id)
      team.add_member(User.find(@participant.user_id),@assignment.id)
end
This <code>else if</code> must be a mistake, so we changed it to:
<code>elsif @participant.team.nil?</code>
 
2. In <code>model/assignment.rb</code>, line 489.
<code>Course.find(self.course_id).get_path</code>
The <code>Course</code> model doesn't have an attribute called <code>get_path</code>, it should be <code>directory_path</code>, so we changed it to
<code>Course.find(self.course_id).directory_path</code>
 
3. In <code>submitted_content/_main.html.erb</code>, line 18.
<% if participant.assignment.is_coding_assignment%>
      <%= link_to "Code Review Dashboard", :controller => 'review_files',
        :action => 'show_all_submitted_files',
        :participant_id => assignment_participant.id,
        :stage => stage %>
    </b><br>
<% end %>
As in this page there doesn't have a parameter called <code>assignment_participant</code>, as it need to get the participant's id, so we changed this line to:
<code>:participant_id => participant.id</code>
 
4. In <code>config/routes.rb</code>. Added one more routes
<code>post :submit_file</code>
 
==Refactoring <code>review_files_controller.rb</code>==
 
1. Changed <code>and</code> and <code>or</code> to <code>&&</code> and <code>||</code> to meet the requirement in the [https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].
 
2. In <code>def get_comments</code>, deleted unused variable:
<code>newobj = ReviewComment.where(review_file_id: params[:file_id])</code>;
 
3. In <code>def show_all_submitted_files</code>, deleted unused variable:
file_path = ReviewFile.get_file(code_review_dir, versions.sort.last,base_filename)
 
4. In <code>def show_all_submitted_files</code>, deleted unused variable:
code_review_dir = ReviewFilesHelper::get_code_review_file_dir(AssignmentParticipant.find(auth[base_filename][versions.sort.last]))
 
5. The method <code>def get_comments</code> is too complex, so we modularized part of its code in review_comments_helper.rb, we created a new method: <code>def self.populate_comments</code>, which helps to <code>handle, comment, authorflag</code> these three variables.
  def self.populate_comments(params, authorflag, comment)
    assignmentparticipant = AssignmentParticipant.find(params[:participant_id])
    current_participant = AssignmentParticipant.where(parent_id: assignmentparticipant[:parent_id], user_id: session[:user].id).first
    if current_participant.id.to_s == params[:participant_id]
      authorflag = 1
    else
      authorflag = 0
    end
    member = []
    if assignmentparticipant.assignment.team_assignment
      assignmentparticipant.team.get_participants.each_with_index {|member1, index|
        member[index] = member1.id
      }
    end
    if (comment[:reviewer_participant_id] ==  current_participant.id)
      handle = "Me :"
      authorflag = 0
    elsif member.include? comment[:reviewer_participant_id] || comment[:reviewer_participant_id] == assignmentparticipant.id
      handle = "Author :"
      authorflag = 0
    else
      handle = "Reviewer"+comment[:reviewer_participant_id].to_s
    end
    return handle, comment, authorflag
  end
6. Rewrited all <code>:key => value</code> to <code>key: value format</code> according to the requirements in the '''Global Rules'''.
 
7. The method <code>def show_code_files_diffIn</code> is too complex, we created a new method: <code>def self.populate_shareObj </code> in <code>review_files_helper.rb</code> to perform part of the <code>show_code_files_diff</code>.
  def self.populate_shareObj(processor)
    first_line_num = []
    second_line_num = []
    first_offset = []
    second_offset = []
    offsetswithcomments_file1 = []
    offsetswithcomments_file2 = []
    first_offset << 0
    second_offset << 0
    first_count = 0
    second_count = 0
    for i in (0..processor.absolute_line_num)
      first_offset = ReviewFile.get_first_offset(processor, i, @first_offset)
      second_offset = ReviewFile.get_second_offset(processor, i, @second_offset)
      first_line_num_new = Hash.new
      first_line_num_new = ReviewFile.get_first_line_num(processor, i, first_count)
      first_line_num << first_line_num[:first_line_num]
      first_count = first_line_num[:first_count]
      second_line_num_new = Hash.new
      second_line_num_new = ReviewFile.get_second_line_num(processor, i,second_count)
      second_line_num << second_line_num[:second_line_num]
      second_count = second_line_num[:second_count]
      # Remove newlines at the end of this line of code
      processor = ReviewFile.get_first_file_array(processor, i)
      processor = ReviewFile.get_second_file_array(processor, i)
      shareObj = Hash.new()
      shareObj['linearray1'] = processor.first_file_array
      shareObj['linearray2'] = processor.second_file_array
      shareObj['comparator'] = processor.comparison_array
      shareObj['linenumarray1'] = first_line_num
      shareObj['linenumarray2'] = second_line_num
      shareObj['offsetarray1'] = first_offset
      shareObj['offsetarray2'] = second_offset
      return first_line_num, second_line_num, first_count, second_count, shareObj
    end
  end
8. In <code>review_files_helper.rb</code>, created a new method: <code>def self.find_review_files</code>, which contains some statements in <code>def show_all_submitted_files</code>.
  def self.find_review_files(participant)
    # Find all files over all versions submitted by the team
    all_review_files = Array.new
    if participant.assignment.team_assignment
      participant.team.get_participants.each_with_index { |member,index|
        all_review_files += ReviewFile.where(author_participant_id: member.id)
      }
    else
      all_review_files = ReviewFile.where(author_participant_id: @participant.id)
    end
    all_review_files
  end
9. In <code>review_files_helper.rb</code>, created a new method: <code>def self.find_review_versions</code>, which contains some statements in <code>def show_all_submitted_files</code>.
  def self.find_review_versions(all_review_files)
    file_version_map = Hash.new
    all_review_files.each_with_index do |each_file,index|
      file_version_map[File.basename(each_file.filepath)] = Array.new unless
      file_version_map[File.basename(each_file.filepath)]
      file_version_map[File.basename(each_file.filepath)] << each_file.version_number
    end
    return file_version_map
  end
==Refactoring <code>submitted_content_controller.rb</code>==
1. Changed <code>and</code> and <code>or</code> to <code>&&</code> and <code>||</code> to meet the requirement in the [https://docs.google.com/document/d/1qQD7fcypFk77nq7Jx7ZNyCNpLyt1oXKaq5G-W7zkV3k/edit Global Rules].
 
2. Rewrited all <code>:key => value</code> to <code>key: value format</code>.
 
3. Rewrited all param['string'] to params[:string].
 
4. Added one more routes <code>post :folder_action</code> to <code>config/routes.rb</code>
 
5. Changed all <code>array.size == 0</code> to <code>array.zero?</code>
 
6. Changed all <code>find_by_x(val)</code> and <code>where("x=val")</code> to <code>where(x: val)</code>
 
7. In <code>def remove_hyperlink</code>, deleted redundant line:
@participant = AssignmentParticipant.find(params[:id])
8. In <code>def download</code>, deleted commented line:
#folder_name = FileHelper::sanitize_folder(@current_folder.name)
 
=Results Screenshot=
After fixing the bug #483, now the upload files function works.
 
[[File:ossp2.png]]
 
The file is stored at:
 
[[File:ossp3.png]]

Revision as of 21:56, 21 March 2015

E1507. Refactoring Review Files Controller & Submitted Content Controller

This page provides a description of the Expertiza based OSS project. This project aimed at refactoring the Review Files Controller & Submitted Content Controller as well as fixing the bug #483

What is Expertiza

Expertiza is a Open Source Rails application where students can submit and peer-review learning objects (articles, code, web sites, etc). It is used in select courses at NC State and by professors at several other colleges and universities. This Open Source application can be cloned from Github, the latest active branch is "Rails 4".

Project Desicription

Bug #483

In "Your works" view, students can only submit links but no files.

This is caused by commit f313711 where the line 13 in submitted_content/_main.html.erb was commented out.

<%#= render partial: 'submitted_content/submitted_files', locals: {participant: @participant, stage: @stage} %>

But after uncommented line 13 in submitted_content/_main.html.erb and refresh the page, the Rails Server stopped responding.

Refactoring Review Files Controller & Submitted Content Controller

What they do

This review_files_controller.rb is responsible for handling the review files of the participants. This controller helps in uploading newer versions of reviews for an assignment and also in displaying all the versions (and diff between versions/code) with the help of submitted_content_controller.rb.

What’s wrong with them

There are quite a few complex functions inside these controllers. These functions can easily be broken up into much more smaller methods with specific functionalities. They also need to be refactored to meet the Global Rules.

What needs to be done

1.Fix this bug #483

2.Break up the complex methods such as get_comments, show_code_file_diff. Anything that can be modularized should be modularized (Single Responsibility)

3.While breaking up the complex methods, look out for possible helper functions. If there are any, move them to the review_files_helper.rb

4.Remove commented out code from the controller

5.Refactor the file based on Global Rules provided at the top of this document

Changes Made

For Bug #483 fixing

Git log can be viewed in commit aa37e2e

1. In submitted_content_controller.rb, line 19.

if @assignment.max_team_size > 1 && @participant.team.nil?
     flash[:error] = "This is a team assignment. Before submitting your work, you must <a style='color: blue;' href='../../student_teams/view/?student_id=#{params[:id]}'>create a team</a>, 
                     even if you will be the only member of the team"
     redirect_to controller: 'student_task', action: 'view', id: params[:id]
else if @participant.team.nil?
     #create a new team for current user before submission
     team = AssignmentTeam.create_team_and_node(@assignment.id)
     team.add_member(User.find(@participant.user_id),@assignment.id)
end

This else if must be a mistake, so we changed it to:

elsif @participant.team.nil?

2. In model/assignment.rb, line 489.

Course.find(self.course_id).get_path

The Course model doesn't have an attribute called get_path, it should be directory_path, so we changed it to

Course.find(self.course_id).directory_path

3. In submitted_content/_main.html.erb, line 18.

<% if participant.assignment.is_coding_assignment%>
     <%= link_to "Code Review Dashboard", :controller => 'review_files',
       :action => 'show_all_submitted_files',
       :participant_id => assignment_participant.id,
       :stage => stage %>
   
<% end %>

As in this page there doesn't have a parameter called assignment_participant, as it need to get the participant's id, so we changed this line to:

:participant_id => participant.id

4. In config/routes.rb. Added one more routes

post :submit_file

Refactoring review_files_controller.rb

1. Changed and and or to && and || to meet the requirement in the Global Rules.

2. In def get_comments, deleted unused variable:

newobj = ReviewComment.where(review_file_id: params[:file_id]);

3. In def show_all_submitted_files, deleted unused variable:

file_path = ReviewFile.get_file(code_review_dir, versions.sort.last,base_filename)

4. In def show_all_submitted_files, deleted unused variable:

code_review_dir = ReviewFilesHelper::get_code_review_file_dir(AssignmentParticipant.find(auth[base_filename][versions.sort.last]))

5. The method def get_comments is too complex, so we modularized part of its code in review_comments_helper.rb, we created a new method: def self.populate_comments, which helps to handle, comment, authorflag these three variables.

 def self.populate_comments(params, authorflag, comment)
   assignmentparticipant = AssignmentParticipant.find(params[:participant_id])
   current_participant = AssignmentParticipant.where(parent_id: assignmentparticipant[:parent_id], user_id: session[:user].id).first
   if current_participant.id.to_s == params[:participant_id]
     authorflag = 1
   else
     authorflag = 0
   end
   member = []
   if assignmentparticipant.assignment.team_assignment
     assignmentparticipant.team.get_participants.each_with_index {|member1, index|
       member[index] = member1.id
     }
   end
   if (comment[:reviewer_participant_id] ==  current_participant.id)
     handle = "Me :"
     authorflag = 0
   elsif member.include? comment[:reviewer_participant_id] || comment[:reviewer_participant_id] == assignmentparticipant.id
     handle = "Author :"
     authorflag = 0
   else
     handle = "Reviewer"+comment[:reviewer_participant_id].to_s
   end
   return handle, comment, authorflag
 end

6. Rewrited all :key => value to key: value format according to the requirements in the Global Rules.

7. The method def show_code_files_diffIn is too complex, we created a new method: def self.populate_shareObj in review_files_helper.rb to perform part of the show_code_files_diff.

 def self.populate_shareObj(processor)
   first_line_num = []
   second_line_num = []
   first_offset = []
   second_offset = []
   offsetswithcomments_file1 = []
   offsetswithcomments_file2 = []
   first_offset << 0
   second_offset << 0
   first_count = 0
   second_count = 0
   for i in (0..processor.absolute_line_num)
     first_offset = ReviewFile.get_first_offset(processor, i, @first_offset)
     second_offset = ReviewFile.get_second_offset(processor, i, @second_offset)
     first_line_num_new = Hash.new
     first_line_num_new = ReviewFile.get_first_line_num(processor, i, first_count)
     first_line_num << first_line_num[:first_line_num]
     first_count = first_line_num[:first_count]
     second_line_num_new = Hash.new
     second_line_num_new = ReviewFile.get_second_line_num(processor, i,second_count)
     second_line_num << second_line_num[:second_line_num]
     second_count = second_line_num[:second_count]
     # Remove newlines at the end of this line of code
     processor = ReviewFile.get_first_file_array(processor, i)
     processor = ReviewFile.get_second_file_array(processor, i)
     shareObj = Hash.new()
     shareObj['linearray1'] = processor.first_file_array
     shareObj['linearray2'] = processor.second_file_array
     shareObj['comparator'] = processor.comparison_array
     shareObj['linenumarray1'] = first_line_num
     shareObj['linenumarray2'] = second_line_num
     shareObj['offsetarray1'] = first_offset
     shareObj['offsetarray2'] = second_offset
     return first_line_num, second_line_num, first_count, second_count, shareObj
   end
 end

8. In review_files_helper.rb, created a new method: def self.find_review_files, which contains some statements in def show_all_submitted_files.

 def self.find_review_files(participant) 
   # Find all files over all versions submitted by the team
   all_review_files = Array.new
   if participant.assignment.team_assignment
     participant.team.get_participants.each_with_index { |member,index|
       all_review_files += ReviewFile.where(author_participant_id: member.id)
     }
   else
     all_review_files = ReviewFile.where(author_participant_id: @participant.id)
   end
   all_review_files
 end

9. In review_files_helper.rb, created a new method: def self.find_review_versions, which contains some statements in def show_all_submitted_files.

 def self.find_review_versions(all_review_files) 
   file_version_map = Hash.new
   all_review_files.each_with_index do |each_file,index|
     file_version_map[File.basename(each_file.filepath)] = Array.new unless
     file_version_map[File.basename(each_file.filepath)]
     file_version_map[File.basename(each_file.filepath)] << each_file.version_number
   end
   return file_version_map
 end

Refactoring submitted_content_controller.rb

1. Changed and and or to && and || to meet the requirement in the Global Rules.

2. Rewrited all :key => value to key: value format.

3. Rewrited all param['string'] to params[:string].

4. Added one more routes post :folder_action to config/routes.rb

5. Changed all array.size == 0 to array.zero?

6. Changed all find_by_x(val) and where("x=val") to where(x: val)

7. In def remove_hyperlink, deleted redundant line:

@participant = AssignmentParticipant.find(params[:id])

8. In def download, deleted commented line:

#folder_name = FileHelper::sanitize_folder(@current_folder.name)

Results Screenshot

After fixing the bug #483, now the upload files function works.

The file is stored at: