CSC/ECE 517 Spring 2020 - E2005. Bookmark enhancements
E2005. Bookmark Enhancements
Introduction
About Expertiza
Expertiza is an open-source project that is built using the Ruby on Rails framework. At its core, it is a highly versatile tool that academic institutions can use to craft learning objectives centered around team projects, peer reviews, and highly-customizable assignments.
Problem Statement
The purpose of this project was to add meaningful enhancements and fixes to the bookmark feature in Expertiza, entities that can be attached to a topic to aid the authors who decide to take on a certain assignment. While the major functionality of the bookmark feature was already present by the time the team embarked on this project (most notably the ability to create/edit and rate bookmarks), many desired functions were conveniently broken or left out.
Completed Stories
Below is a breakdown of the stories that were drawn up and completed for this project:
1. Need a way to view all responses to the bookmark questionnaires.
2. Modify permissions for deleting bookmarks.The person who creates the bookmark, the team for whom the bookmark is meant, and the instructor, should be able to delete.
3. "View bookmarks" link on student_task/view breaks if the student has not selected a topic yet.
4. Bookmark rating questionnaire should include question asking the reviewer whether or not the bookmark appears to have been used by the author. Get the bookmark questionnaire functioning and add to the bookmark list page.
5. Fix issue in which users should not be able to review their own bookmark using the questionnaire, but currently can.
6. Add a number next to/inside the icon with the number of current bookmark in order to make it clear whether a bookmark exists for a topic.
7. Add a "View bookmarks" link to the assignment view page for easier access.
8. Add rating to the bookmark questionnaire and use that rating to calculate the average instead of using the current dropdown.
9. A student should not be able to rate his/her own bookmark.
10. Add URL to bookmark list for assignment topic on the assignment page, to make viewing bookmarks easier.
11. Instructors cannot currently see bookmarks (gets an error message saying instructors cannot create bookmarks).
12. "Back" button from Bookmarks list is broken.
13. When creating a bookmark with an empty description field, the notice says the bookmark was successfully created even though it fails.
14. "Bookmark ratings" should be a type of rubric when you go to Manage > Questionnaires. Although 'Bookmark Rating' is already a type of rubric, it isn't listed when hovering over Manage... > Questionnaires
15. Create a way to mark a bookmark that was rated to be helpful by all reviewers, on average.
16. Students can add/view bookmarks when "Allow participants to create bookmarks?" box is unchecked for the assignment.
Code Modifications
Fix the "Back" button: When either backing out of creating or viewing/editing a bookmark, the back functionality does not work, both prompting errors. Issue has been fixed and users can once again go back to the appropriate page.
Changed files:
- app/views/bookmarks/list.html.erb
<%= link_to 'Back', '#', :onclick => 'pageBack()' %>
<script> .... function pageBack() { history.back() } </script>
- app/views/bookmarks/new.html.erb
<%= link_to 'Back', '#', :onclick => 'pageBack()' %>
<script> .... function pageBack() { history.back() } </script>
- app/views/bookmarks/edit.html.erb
<%= link_to 'Back', '#', :onclick => 'pageBack()' %>
<script> .... function pageBack() { history.back() } </script>
Pull request can be found here
Commit for "Back" capability when updating bookmark can be found here
Check whether text field is present when creating/updating bookmark:
Previously, when a bookmark was created/updated and the corresponding "Title", "URL", or "Description" text fields were not filled in, the bookmark was not created or updated sans any error or warning. In fact, the user would be taken to the list of bookmarks available, forcing him/her to go back to the page corresponding to the bookmark create/edit page. This fix prompts users with an error indicating which text field needs to be filled in in order to fulfill the particular bookmark create/edit function.
Changed files:
- app/views/bookmarks/new.html.erb
<!-- :required attribute checks to see if title, url, and description are all present --> <p> <%= label_tag 'Title' %><br/> <%= text_field_tag :title, params[:title], :required => true %><br/><br/> <%= label_tag 'Url' %><br/> <%= text_field_tag :url, params[:url], :required => true %><br/><br/> <%= label_tag 'Description' %><br/> <%= text_area_tag :description, params[:description], :required => true %><br/> </p>
- app/views/bookmarks/edit.html.erb
<!-- :required attribute checks to see if title, url, and description are all present --> <p> <%= label_tag 'Title' %><br/> <%= f.text_field :title, :required => true %><br/><br/> <%= label_tag 'Url' %><br/> <%= f.text_field :url, :required => true %><br/><br/> <%= label_tag 'Description' %><br/> <%= f.text_area :description, :required => true %><br/> </p>
Pull request can be found here
Change average bookmark rating to be based on questionnaire:
The rating system for the bookmarks before these changes were elementary in nature - there was a drop-down menu to choose your particular rating for a bookmark while there was an average calculator just to the left of the aforementioned column. The new changes introduced allows the "Your rating" and "Avg. rating" columns for a particular bookmark to be calculated based on the scores given to the various questions present in a given bookmark questionnaire. The "Avg. rating" is calculated based on the mean rating of all the bookmark questionnaires scored by every reviewer while "Your rating" is simply the mean of the scores that you (the user) gave to all the questions on the questionnaire. The integer '5' used in calculating both types of average scores was used because of the fact that there are a total of five stars for each questionnaire question.
Qustionnaire for fourth bookmark listed above (do your own calculation to find the mean for 'Your rating'):
Changed files:
- app/controllers/bookmarks_controller.rb
helper_method :specific_average_score helper_method :total_average_score
# calculate average questionnaire score for 'Your rating' for specific bookmark def specific_average_score(bookmark) if bookmark.nil? return '-' else assessment = SignUpTopic.find(bookmark.topic_id).assignment questions = assessment.questionnaires.where(type: 'BookmarkRatingQuestionnaire').flat_map(&:questions) responses = BookmarkRatingResponseMap.where( reviewed_object_id: assessment.id, reviewee_id: bookmark.id, reviewer_id: AssignmentParticipant.find_by(user_id: current_user.id).id).flat_map {|r| Response.where(map_id: r.id) } score = Answer.get_total_score(response: responses, questions: questions) if score.nil? return '-' else (score * 5.0 / 100.0).round(2) end end end
# calculate average questionnaire score for 'Avg. rating' for specific bookmark def total_average_score(bookmark) if bookmark.nil? return '-' else assessment = SignUpTopic.find(bookmark.topic_id).assignment questions = assessment.questionnaires.where(type: 'BookmarkRatingQuestionnaire').flat_map(&:questions) responses = BookmarkRatingResponseMap.where( reviewed_object_id: assessment.id, reviewee_id: bookmark.id).flat_map {|r| Response.where(map_id: r.id) } totalScore = Answer.compute_scores(responses, questions) if totalScore[:avg].nil? return '-' else (totalScore[:avg] * 5.0 / 100.0).round(2) end end end
- app/views/bookmarks/list.html.erb
<!-- total average rating used for 'Avg. rating' --> <% totalAvg = total_average_score(bookmark) %> <% if totalAvg != 0 %> <%= totalAvg %> <% else %> <%= '-' %> <% end %>
<!-- specific average rating used for 'Your rating' --> <% specAvg = specific_average_score(bookmark) %> <% if specAvg != 0 %> <%= specAvg %> <% else %> <%= '-' %> <% end %>
Pull request can be found here
Addition of badges for exceptionally helpful bookmarks:
Originally, no badge system was setup for bookmarks that have proven to be helpful guides for other students taking on the same project. The new changes introduced allows bookmarks to be attached to bookmarks with exceptionally good average ratings (i.e, above a rating of 3). A badge is signified by a full star while the absence of a badge is represented by an empty star.
Changed files:
- app/views/bookmarks/list.html.erb
<th class="head">Badge</th> <td> <!-- badge rewards for bookmarks --> <!-- full star denotes presence of badge --> <!-- empty star denotes absence of badge --> <% if totalAvg.to_f > 3 %> <span class="glyphicon glyphicon-star"></span> <% else %> <span class="glyphicon glyphicon-star-empty"></span> <% end %> </td>
Pull request can be found here
Users cannot rate bookmarks they've uploaded.
We wanted to make sure that users cannot rate bookmarks that they uploaded.
Changed files:
- app/views/bookmarks/list.html.erb
<!--Users can't rate their own bookmarks.--> <% if session[:user].id != bookmark.user_id %> # ... code for rating the bookmarks <% else %> <%= '-' %> <% end %>
Pull request can be found here
Users cannot review bookmarks they've uploaded using the questionnaire.
We also wanted to make sure that users cannot review bookmarks that they uploaded using the questionnaires.
Changed files:
- app/views/bookmarks/list.html.erb
<!--Users can only add/edit/view review other users' bookmarks.--> <% if session[:user].id == bookmark.user_id %> # ... code for reviewing bookmarks using the questionnaire <% else %> <%= '-' %> <% end %>
Pull request can be found here
Users should be able to see the number of bookmarks from the topics list.
Previously, users could add bookmarks, but could not tell how many bookmarks were provided for each topic (if any) without clicking the "View bookmarks" icon. This UI change displays the number of bookmarks for the topic inside the view bookmarks icon from the topic list view so that users don't need to click through each topic individually.
Changed files:
- app/views/sign_up_sheet/_actions.html.erb
<p class="fa fa-stack-2x fa-inverse" style='font-size: 1.0em; padding-top: 2px; font-weight: bold;'> <%= Bookmark.where(topic_id: topic.id).length.to_s %> </p>
Pull request can be found here
UI changes to make finding your bookmarks easier:
We added a "View Bookmarks" link to the student task view, that takes the student directly to the bookmarks that have been submitted for their topic. This code was then modified such that the link is greyed out if the student does not have a topic, and is hidden if bookmarks are not enabled for the assignment.
Changed files:
- app/controllers/student_task_controller.rb
- app/views/student_task/view.html.erb
<% if @use_bookmark %> <li>> <% if @topic_id and @assignment.submission_allowed(@topic_id) %> <%= link_to "View bookmarks", :controller=>'bookmarks', :action=> 'list', :id => @topic_id %> (View bookmarks others have submitted for your topic) <% else %> <font color="gray">View bookmarks (You have to choose a topic first) <% end %> </li> <% end %>
Relevant commits can be found here here and here
Grey out add/view bookmarks link on the topic page if bookmarks are not enabled. Previously, students could submit and view bookmarks even if bookmarks were disabled for the assignment. Now these options are hidden.
Changed files:
- app/views/sign_up_sheet/_actions.html.erb
<% if @use_bookmark %> <%= link_to :controller=>'bookmarks', :action=> 'list', :id => topic.id do %> <span class="fa-stack fa-md" title='View topic bookmarks'> <i class="fa fa-bookmark fa-stack-1x fa-2x"> <p class="fa fa-stack-2x fa-inverse" style='font-size: 1.0em; padding-top: 2px; font-weight: bold;'> <%= Bookmark.where(topic_id: topic.id).length.to_s %> </p> </span> <% end %> <%= link_to :controller=>'bookmarks', :action=> 'new', :id => topic.id , :assignment_id => params[:assignment_id] do %> <span class="fa-stack fa-md" title='Add bookmark to topic'> <i class="fa fa-bookmark fa-stack-1x fa-2x"> <i class="fa fa-plus fa-stack-1x fa-inverse" style='font-size: .5em'> </span> <% end %> <% else %> <span class="fa-stack fa-md" title='View topic bookmarks'> <i class="fa fa-bookmark fa-stack-1x fa-2x" style="opacity: 0.3;"> <% end %>
- app/views/sign_up_sheet/_table_header.html.erb
<th width="10%"> Bookmarks <% unless @use_bookmark %> (disabled) <% end %> </th>
Commit can be found here
Modify Bookmark delete permissions.
Bookmarks should be deletable by the user who created the bookmark, a teammate of the user who provided the bookmark, and the instructor.
Changed files:
- app/views/bookmarks/list.html.erb
<!--Editing/destroying bookmarks is available to the reviewing user, the reviewing user's team, and the instructor.--> <% is_teammate = false %> <% team = SignedUpTeam.find_by(topic_id: @topic.id) rescue nil %> <% if team %> <% teams_users = TeamsUser.where(['team_id = ?', team.team_id]) %> <% is_teammate = teams_users.select {|tu| tu.user_id == session[:user].id}.size > 0 %> <% end %> <% if bookmark.user_id == session[:user].id or is_teammate or ['Instructor'].include? @current_role_name %> <td><%= link_to 'Edit Bookmark', :action => 'edit', :id => bookmark.id %></td> <td><%= link_to 'Destroy Bookmark', bookmark, :confirm => "Delete bookmark \"#{bookmark.title}\"?", :method => :delete %></td> <% end %>
Pull request can be found here
Fix the ability to create bookmark questionnaires and use in assignments. Previously, questionnaires for things like Teammate Reviews could be created and used in assignments. Users could fill these out and the scores would be stored for later reference by TAs and instructors. The questionnaire for bookmark reviews was previously not functional, but now instructors can create new bookmark questionnaires and assign them to assignments.
Changed files:
- app/controllers/questionnaires_controller.rb
@questionnaire = Object.const_get(params[:model].split.join).new if Questionnaire::QUESTIONNAIRE_TYPES.include? params[:model].split.join .... if %w[AuthorFeedback CourseSurvey TeammateReview GlobalSurvey AssignmentSurvey BookmarkRating].include?(display_type)
- app/controllers/questionnaires_controller.rb
.... when "bookmark" bookmark = Bookmark.find(@map.response_map.reviewee_id) redirect_to controller: 'bookmarks', action: 'list', id: bookmark.topic_id .... "BookmarkRatingResponseMap"
- app/models/bookmark_rating_response_map.rb
.... self.assignment.questionnaires.find_by(type: 'BookmarkRatingQuestionnaire')
- app/views/bookmarks/list.html.erb
....
<!--Users can only add/edit/view review other users' bookmarks.--> <% if bookmark.user_id != session[:user].id %> <% assignment_participant = AssignmentParticipant.find_by(user_id: session[:user].id) %> <% map = BookmarkRatingResponseMap.where(reviewed_object_id: @topic.assignment.id, reviewer_id: assignment_participant.id, reviewee_id: bookmark.id).first %> <% if map.nil? %> <% map = BookmarkRatingResponseMap.create(reviewed_object_id: @topic.assignment.id, reviewer_id: assignment_participant.id, reviewee_id: bookmark.id) %> <% end %> <% review = map.response.last %> <% if review.nil? %> <%= link_to "Review", {:controller => 'response', :action => 'new', :id => map.map_id, :return => "bookmark"} %> <% else %> <%= link_to "View", {:controller => 'response', :action => 'view', :id => review.id} %> <%= link_to "Edit", {:controller => 'response', :action => 'edit', :id => review.id, :return => "bookmark"} %> <% end %> <% else %> <%= '-' %> <% end %>
<% if bookmark.user_id == session[:user].id %> <td><%= link_to 'Edit', :action => 'edit', :id => bookmark.id %></td> <td><%= link_to 'Destroy', bookmark, :confirm => "Delete bookmark \"#{bookmark.title}\"?", :method => :delete %></td> <td><%= link_to 'Edit Bookmark', :action => 'edit', :id => bookmark.id %></td> <td><%= link_to 'Destroy Bookmark', bookmark, :confirm => "Delete bookmark \"#{bookmark.title}\"?", :method => :delete %></td> <% end %>
- app/views/response/view.html.erb
<% if !(@map.instance_of? TeammateReviewResponseMap) && !@map.survey? && !(@map.instance_of? BookmarkRatingResponseMap) %> .... Pull request can be found here Instructors should have the ability to view all bookmark responses. Instructors should have a way to view all the responses to the bookmark questionnaires so that can see which bookmarks provided were deemed useful. Changed files:
- app/helpers/report_formatter_helper.rb
def bookmark_rating_response_map(params, _session = nil) assign_basics(params) @reviewers = BookmarkRatingResponseMap.bookmark_response_report(@id) @topics = @assignment.sign_up_topics end
- app/models/bookmark_rating_response_map.rb
class BookmarkRatingResponseMap < ReviewResponseMap def self.bookmark_response_report(id) BookmarkRatingResponseMap.select("DISTINCT reviewer_id").where("reviewed_object_id = ?", id) end
- app/views/reports/_bookmark_rating_report.html.erb
<%= create_report_table_header("Reviewed By" => "16%", "Topic" => "14%", "Bookmark Review" => "20%", "Submitted By" => "20%", "Last reviewed at" => "20%") %> <%@l = -1 %> <% @reviewers.each do |r| %> <% @user = User.find(Participant.find(r.reviewer_id).user_id) %> <% @bookmark_rating_response_maps = BookmarkRatingResponseMap.where(reviewer_id: r.reviewer_id, reviewed_object_id: @id) %> <% maps = @bookmark_rating_response_maps.select { |m| !Response.where(map_id: m.id).first.blank? and m.reviewee and m.reviewee.user_id != @user.id }%> <%@l = @l+1 %> <% (@l % 2 == 0) ? @bgcolor = "#ffffff" : @bgcolor = "#f9f9f9" %> <% if maps.count > 0 %> <td bgcolor=<%= @bgcolor %> rowspan= <%= maps.count %>> <% @reviewer_name = @user.fullname(session[:ip]) %> <%= link_to @reviewer_name, :controller => 'popup', :action => 'reviewer_details_popup', :id => r.reviewer_id, :assignment_id => @id %> <% maps.each do |map| %> <% @reviewee = map.reviewee %> <td bgcolor=<%= @bgcolor %> align="left" colspan=1> <% topic = SignUpTopic.find(@reviewee.topic_id) %> <%= topic.topic_name %> <td id = "green" bgcolor=<%= @bgcolor %> align="left" colspan=1> <%= link_to @reviewee.title, {:controller => 'response', :action => 'view', :id => map.response.last.id}, :title => "Click here to view this bookmark review" %> <td id = "green" bgcolor=<%= @bgcolor %> style="color:#DD3300" align="left" colspan=1> <% reviewed_by_user = User.find(@reviewee.user_id).name %> <%= link_to reviewed_by_user, impersonate_impersonate_path(:user => {:name => reviewed_by_user}), :method => :post, :title => "Click here to impersonate this user" %> <td bgcolor=<%= @bgcolor %> align="left"> <% @bookmark_review_response = Response.where(map_id: map.id).first %> <%= @bookmark_review_response.updated_at.to_time.strftime("%m/%d/%Y - %I:%M%p") %> <% end %> <% end %> <% end %>
- app/views/reports/_searchbox.html.erb
.... <option value='BookmarkRatingResponseMap' > Bookmark Review Report </option> .... <% elsif @type == "BookmarkReviewResponseMap" %> <h1> Bookmark review report for <%= @assignment.name%> </h1> ....
- app/views/reports/response_report.html.haml
- elsif @type == "BookmarkRatingResponseMap" = render :partial => 'bookmark_rating_report'
Pull request can be found here
DB Diagram
Testing Plan
Testing from the UI
- Create a Bookmark Questionnaire
- After logging in as the instructor, go to Manage > Questionnaires.
- Find 'Bookmark Rating' and click the '+' to create a new questionnaire.
- Give a name for this questionnaire, leave the min and max score at 0 and 5 respectively, and click 'Create'.
- Go to Manage > Questionnaires and click on 'Bookmark Rating' to view all of the questionnaires. Click the edit icon for the questionnaire you just created.
- Select 'Add 1 more Criterion question(s)'.
- For the question, enter "Does this bookmark appear to have been used by the author?" and leave the other fields blank. This question will be helpful in determining how useful the bookmark was.
- Click 'Save bookmark rating questionnaire'. Now this questionnaire can be used in assignments.
- Enable Bookmarks
- After logging in as the instructor, go to Manage > Assignments.
- Choose an assignment that will be used for testing and have bookmarks enabled and select the edit icon under Actions.
- Under Topics Tab select 'Allow participants to create bookmarks?'.
- Go to Rubrics tab, under 'Bookmark Rating' select the Bookmark review questionnaire that was previously created to use for reviewing the bookmarks.
- Add a Bookmark to a Topic
- Log in as a student who is a participant of the assignment with bookmarks enabled and select that assignment.
- Select a "Signup sheet" to see the list of available topics.
- Choose a topic and select the 'Add bookmark to topic' icon from the Bookmarks column. The 'Add bookmark to topic' icon has a '+' sign.
- Fill in all the fields for the bookmark, including Title, Url, and Description and click 'Add new bookmark'.
- You should now see a page listing all bookmarks for this topic.
- Viewing all Bookmarks for a Topic
- Log in as a student who is a participant of the assignment with bookmarks enabled (or an instructor) and select that assignment.
- Select a "Signup sheet" to see the list of available topics.
- The number of bookmarks for each topic should be displayed visually inside the 'View topic bookmarks' icon in the bookmarks column.
- Click the 'View topic bookmarks icon' to see a list of all bookmarks for this topic.
- Editing and Destroying Bookmarks for a Topic
- Perform this test with each of the following users: an instructor, a user who is assigned to the topic, and a teammate of the user who is assigned to the topic.
- Log in with the user and select the assignment with bookmarks enabled.
- Select a "Signup sheet" to see the list of available topics.
- Click the 'View topic bookmarks icon' to see a list of all bookmarks for this topic.
- The user should see links to 'Edit Bookmark' and 'Destroy Bookmark' next to a bookmark only if the user is an instructor, the user submitted the bookmark, or the user is a teammate of the user who submitted the bookmark.
Automated Testing with RSpec
The current version of Expertiza does not have any tests for the bookmark controller or model. We intend on adding comprehensive RSpec tests for all changes we have added to controller classes and unit tests for model classes.
Code Coverage
Application Deployment
This web application deployed on VCL is located at http://152.46.17.220:8080
Note: To aid in testing, we have created an assignment called "Bookmarks Test Assignment" as instructor6. The students assigned to this assignment include student7339, student7340, and student7341.
Team Information
Danielle Hancock
Eric Peden
Hosung Hwang
Mentor: Abhirav Kariya