CSC/ECE 517 Fall 2019 - E1939. OSS Project Juniper: Bookmark enhancements

From Expertiza_Wiki
Jump to navigation Jump to search

Expertiza

Expertiza is an educational web application created and maintained by the joint efforts of the students and the faculty at NCSU. It’s an open source project developed on Ruby on Rails platform and the code is available on Github. It allows students to review each other’s work and improve their work upon this feedback. Students and Instructors (including TA's) use this application though their credentials. Instructors can add new projects, assignments etc as well edit the previous ones and at a later stage can see the student submission and grade them. They can even put a time limit (deadline) for submitting the assignment. Students can form teams for the projects, submit their work through handles (Wiki page, link to a video etc). Students can even review their teammates and other peers, as well give them any suggestions if required


Review Assessment Credentials The credentials for Peer review assessment for Bookmark Enhancement project are Instructor Login: username => instructor6 password=>password

Accounts for Impersonation: username => student6340, student6341 Assignment => Exercises, CSC456, Fall2015


Bookmark Functionality in Expertiza

Expertiza features the bookmarking functionality which allows users to help the author of the project by suggesting insights. Let’s say there are five topics that I’m interested in and would like to contribute to, but I can only choose one. Well, for the other topics, I’m allowed to submit hyperlinks to pages that I think would help the author do the work. On each line of the signup sheet are two icons, one for adding a bookmark to the topic, and another for viewing bookmarks on the topic. The bookmarks are attached to each project topic and user can suggest by filling up a questionnaire. As soon as a user creates a bookmark, the project author is able to view all the bookmarks that are created for his project. The author can give a feedback on the bookmark that he has received which helps even the user know the usefuless of his bookmark.


Bookmark Enhancements

The Bookmark functionality in expertiza is in its nascent stage which allows user to provide feedback on the projects that he is interested in. It also allows the author to rate the bookmarks that he has received for his project. Project Juniper Bookmark Enhancements is an attempt to make the bookmarks more user-friendly and credible. We have improved the functionality for an author to descriptively evaluate the bookmark that he has received on his project using rubrics as set by the instructor.

Bugs that were identified

  • Fixing the “Back” button
  • Validations on the form for adding bookmarks were missing
  • Allowed the creator of bookmark to rate himself and fixed the logic for calculating average rating
  • Bookmark Rating Questionnaire could not be created


Design and Implementation

Fixing the Back button: When user visits “Create Bookmarks" and "View Bookmarks", the back button was not functional which refrained the user from going back to the Signup-sheet. Now this issue has been fixed which in future will allow to any contributor to use this back functionality.


Earlier:

Files Changed:

app/controllers/bookmarks_controller.rb
 def list
   @participant = Participant.where(user_id: session[:user].id).first
   @bookmarks = Bookmark.where(topic_id: params[:id])	   
   @topic = SignUpTopic.find(params[:id])	   
 end	 
 def new	 
   @participant = Participant.where(user_id: session[:user].id).first
   @topic = SignUpTopic.find(params[:id])	    
   @bookmark = Bookmark.new	 
 end	 
app/views/bookmarks/list.html.erb
  <%= link_to 'Back', :controller=> 'sign_up_sheet', :action=>'list', :id => @participant.id, :assignment_id => @topic.assignment_id %>


The changed code can be found here

The screencast can be found here:


Bookmark Validations The form for creating a new bookmark allowed malformed URLs to be entered into the system. Now, the bookmarks can be added only when user enters legitimate URL as well as all the fields are completely filled. Validations were added as a security measure to prevent misuse.

Files Changed:

app/controllers/bookmarks_controller.rb
    def update
    ....
    begin
     @bookmark.update_attributes!(url: params[:bookmark][:url], title: params[:bookmark][:title], description: params[:bookmark][:description])
     ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Your bookmark has been successfully updated!', request)
     flash[:success] = 'Your bookmark has been successfully updated!'
   rescue StandardError
     ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO.to_s, request)
     flash[:error] = 'Bookmark could not be updated: ' + $ERROR_INFO.to_s
   end
   ....
   end
app/models/bookmark.rb
    class Bookmark < ActiveRecord::Base
    ....
    # validates if the url provided is of a valid format
    validates_format_of :url, :multiline => true, :with => /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/, :on => :create
    ....
    end

The changed code can be found here:

The screencast can be found here:


Self Rating of Bookmarks and average calculation When reviewing the bookmark, the average rating for that bookmark shown was calculated wrongly and showed average rating for the bookmark that wasn’t reviewed. Also, the user who created the bookmark could rate himself. Now, the user cannot rate his own bookmarks and the average rating is calculated perfectly after one or more people have reviewed it.

Files Changed:

app/models/bookmark_rating.rb
   # Calculates the rating of a bookmark when review type is a rubric and not a dropdown
  def average_based_on_rubric(bookmark)
      if bookmark.nil?
         0
      else
         assignment = SignUpTopic.find(bookmark.topic_id).assignment
         questions = assignment.questionnaires.where(type: 'BookmarkRatingQuestionnaire').flat_map(&:questions)
         responses = BookmarkRatingResponseMap.where(
             reviewed_object_id: assignment.id,
             reviewee_id: bookmark.id
         ).flat_map {|r| Response.where(map_id: r.id) }
         scores = Answer.compute_scores(responses, questions)
         if scores[:avg].nil?
           0
          else
           (scores[:avg] * 5.0 / 100.0).round(2)
         end
       end
     end
  
  # fetches the previously added responses to rate a bookmark   
  def self.get_bookmark_rating_response_map(bookmark, current_user)
     BookmarkRatingResponseMap.find_by(
         reviewed_object_id: SignUpTopic.find(bookmark.topic_id).assignment.id,
         reviewer_id: AssignmentParticipant.find_by(user_id: current_user.id).id,
         reviewee_id: bookmark.id
       )
app/views/bookmarks/list.html.erb
      ....

<a href=<%= "http://#{bookmark.url}"%> target='_blank'><%=bookmark.title %> <%=truncate(bookmark.description, length: 100) %>

       <% @bookmark_ratings = BookmarkRating.where(bookmark_id: bookmark.id) %>
       <% @bookmark_ratings.to_a.reject! {|bookmark_rating| bookmark_rating.user_id == Bookmark.find(bookmark_rating.bookmark_id).user_id} %>
       <% sum = 0 %>
       <% @bookmark_ratings.each do |bookmark_rating| %>
         <% sum += bookmark_rating.rating %>
       <% end %>
         <% if has_dropdown?(@topic) %>
           <% if @bookmark_ratings.size > 0 %>
             <%= (sum * 1.0 / @bookmark_ratings.size).round(1) %>
           <% else %>
             <%= '-' %>
           <% end %>
         <% else %>
           <% avg = BookmarkRating.average_based_on_rubric(bookmark) %>
           <%= avg == 0 ? '-' : avg %>
         <% end %>
         <% if bookmark.user.id != current_user.id %>
           <% if has_dropdown?(@topic) %>
             <% if BookmarkRating.exists?(bookmark_id: bookmark.id, user_id: session[:user].id) %>
               <% rating = BookmarkRating.where(bookmark_id: bookmark.id, user_id: session[:user].id).first.rating.to_s %>
             <% else %>
               <% rating = "0" %>
             <% end %>
             <%= form_tag :action => "save_bookmark_rating_score", :id => bookmark.id do %>
               <% params[:rating] = rating %>
               <select id=<%= bookmark.id %> name="rating" style="font-size: 10px">
                 <% (0..5).each do |i| %>
                   <option value=<%= i.to_s %>
                             <% if params[:rating] == i.to_s %>
                               selected
                      <% end %>
                    >
                      <%= i.to_s %>
                    </option>
                 <% end %>
               </select>
               <% if BookmarkRating.where(bookmark_id: bookmark.id, user_id: session[:user].id).first.blank? %>
                 <%= button_tag "Rate", {:id=>'button'+bookmark.id.to_s,:style=>"font-size:10px; display:none;"} %>
               <% else %>
                 <%= button_tag "Update", {:id=>'button'+bookmark.id.to_s,:style=>"font-size:10px; display:none;"} %>
               <% end %>
             <% end %>
           <% else %>
             <% bookmark_rating_response_map = BookmarkRating.get_bookmark_rating_response_map(bookmark, current_user) %>
             <% if bookmark_rating_response_map.nil? || bookmark_rating_response_map.response.size == 0 %>
               <%= link_to "Begin", :action => "new_bookmark_review", :id => bookmark.id %>
             <% else %>
               <%= link_to "View", view_response_index_path(id: bookmark_rating_response_map.response.first.response_id) %>
               <%= link_to "Edit", edit_response_path(id: bookmark_rating_response_map.response.first.response_id, return: 'bookmark') %>
             <% end %>
           <% end %>
         <% end %>

<% if bookmark.user_id == session[:user].id %> <%= link_to 'Edit', :action => 'edit', :id => bookmark.id %> <%= link_to 'Destroy', bookmark, :confirm => "Delete bookmark \"#{bookmark.title}\"?", :method => :delete %>

       <% end %>
          ....
app/controllers/bookmarks_controller.rb
  1. method to check if a dropdown is used for rating bookmarks
  def has_dropdown?(topic)
    bookmark_rating_questionnaire = topic.assignment.questionnaires.where(type: 'BookmarkRatingQuestionnaire')
    if bookmark_rating_questionnaire[0].nil?
      true
    else
      false
    end
  end

The changed code can be found here:


Review bookmark using rubric functionality The bookmark functionality earlier only allowed for the users to rate the bookmark and not give feedback about the the quality of the Bookmark. Now, feature is added so that the instructor can decide whether to allow for bookmark to be just rated or a have a rubric . The instructor can customize the questions in the rubric. The rubric once created by the instructor can be used for multiple assignments and also multiple rubrics can be created for different types of assignments.

Files Modified

app/controllers/bookmarks_controller.rb
   ..... 
   # Saves the responses to the bookmark review questionnaire.
   # If a previous response exists it updates it.
   def new_bookmark_review
       bookmark = Bookmark.find(params[:id])
       topic = SignUpTopic.find(bookmark.topic_id)
       assignment_participant = AssignmentParticipant.find_by(user_id: current_user.id)
       response_map = BookmarkRatingResponseMap.where(
         reviewed_object_id: topic.assignment.id,
         reviewer_id: assignment_participant.id,
         reviewee_id: bookmark.id
       ).first
       if response_map.nil?
         response_map = BookmarkRatingResponseMap.create(
           reviewed_object_id: topic.assignment.id,
           reviewer_id: assignment_participant.id,
           reviewee_id: bookmark.id
         )
       end
       redirect_to new_response_url(id: response_map.id, return: 'bookmark')
     end
     .....
app/controllers/questionnaires_controller.rb
   if %w[AuthorFeedback CourseSurvey TeammateReview GlobalSurvey AssignmentSurvey BookmarkRating].include?(display_type)
         display_type = (display_type.split /(?=[A-Z])/).join("%")
   end
       @questionnaire.display_type = display_type
app/controllers/response_controller.rb
       when "bookmark"
           bookmark = Bookmark.find(@map.response_map.reviewee_id)
            redirect_to controller: 'bookmarks', action: 'list', id: bookmark.topic_id
    
      def set_questionnaire_for_new_response
          .
          .
             "GlobalSurveyResponseMap",
             "BookmarkRatingResponseMap"
             @questionnaire = @map.questionnaire
          end
      end


The screencast can be found here:

Testing Plan

Testing From UI

  • Enable Bookmarks
  1. After logging in as instructor, go to Manage > Assignments
  2. Select Edit under Actions for assignment
  3. Under Topics Tab select 'Allow participants to create bookmarks?' to allow bookmarks
  4. Go to Rubrics tab, under 'Bookmark Rating' select the Bookmark review questionnaire to use the rubric for reviewing the bookmarks , select None for dropdown.

Note: When 'Bookmark Rating' is 'None', the error the error 'You did not specify all the necessary rubrics. You need [BookmarkRating] of assignment Exercises before saving the assignment. You can assign rubrics here.' is out of scope of the current project and the error can safely be ignored from point of view of this project '

  • Fixing the back Button & Validations
  1. Log in as an instructor and impersonate as a student using the credentials given above
  2. Select ‘Exercises’ assignment and go to the Signup sheet
  3. We can see a list of projects with 2 columns to add or remove the Bookmark, select any of them
  4. You’ll be redirected to the corresponding page where the back button will be visible
  5. Select add bookmark and the form can be tested for Validations.
  • Create new Bookmark Rating Rubric
  1. As an instructor, go to Manage>Questionnaires and select Bookmark Rating field
  2. Create a new rubric with required details
  3. Start adding questions. This can be done by manually entering into the system or importing Questionnaire.
  • View Bookmarks
  1. Log in as an instructor and impersonate as user using the credentials mentioned above and then select assignment "Exercises"
  2. Add bookmarks to other topics.
  3. The owner of that project should be able to see all the bookmarks created for his project and can rate the bookmark through the way instructor has defined it (rating or rubric).


Automated Testing with RSpec

The current version of expertiza did not have any test for the BookmarksController and the Bookmarks model. Using the test driven development(TDD) approach, we have added an exhaustive set of RSPEC tests for BookmarksController, to test all the modifications we have done to the code of the controller class. We have also added unit tests to the bookmarks model. The tests can be executed using the "bundle exec rspec filename" command as shown below.

  user-expertiza $bundle exec rspec spec_file_path
  [Coveralls] Set up the SimpleCov formatter.
  [Coveralls] Using SimpleCov's 'rails' settings.
  Randomized with seed 5067
  ......................
  Finished in 1 minute 50.34 seconds (files took 10.6 seconds to load)
  22 examples, 0 failures
  Randomized with seed 5067

Rspec testing videos can be found here:

Deployment

This application with the mentioned changes have been deployed on VCL and can be found at http://152.46.19.205:8080

Future Scope

  • Giving credit to the author of the bookmark for his contribution

References

  1. Github Link: https://github.com/srujana13/expertiza
  2. Pull Request: https://github.com/expertiza/expertiza/pull/1540/
  3. http://wiki.expertiza.ncsu.edu/index.php/E1830_OSS_Project_Juniper:_Bookmark_enhancements
  4. Expertiza on Github https://github.com/expertiza/expertiza

Contributors

  1. Tanvi Pandit (tmpandi2@ncsu.edu)
  2. Abhirav Kariya (akariya@ncsu.edu)
  3. Srujana Rachakonda (srachak@ncsu.edu)
  4. Mentor Edward Gehringer (efg@ncsu.edu)