CSC/ECE 517 Fall 2019 - E1939. OSS Project Juniper: Bookmark enhancements
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.
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
- 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
- After logging in as instructor, go to Manage > Assignments
- Select Edit under Actions for assignment
- Under Topics Tab select 'Allow participants to create bookmarks?' to allow bookmarks
- 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
- Log in as an instructor and impersonate as a student using the credentials given above
- Select ‘Exercises’ assignment and go to the Signup sheet
- We can see a list of projects with 2 columns to add or remove the Bookmark, select any of them
- You’ll be redirected to the corresponding page where the back button will be visible
- Select add bookmark and the form can be tested for Validations.
- Create new Bookmark Rating Rubric
- As an instructor, go to Manage>Questionnaires and select Bookmark Rating field
- Create a new rubric with required details
- Start adding questions. This can be done by manually entering into the system or importing Questionnaire.
- View Bookmarks
- Log in as an instructor and impersonate as user using the credentials mentioned above and then select assignment "Exercises"
- Add bookmarks to other topics.
- 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
- Github Link: https://github.com/srujana13/expertiza
- Pull Request: https://github.com/expertiza/expertiza/pull/1540/
- http://wiki.expertiza.ncsu.edu/index.php/E1830_OSS_Project_Juniper:_Bookmark_enhancements
- Expertiza on Github https://github.com/expertiza/expertiza
Contributors
- Tanvi Pandit (tmpandi2@ncsu.edu)
- Abhirav Kariya (akariya@ncsu.edu)
- Srujana Rachakonda (srachak@ncsu.edu)
- Mentor Edward Gehringer (efg@ncsu.edu)