CSC/ECE 517 Fall 2019 - Project E1973. Team Based Reviewing: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(37 intermediate revisions by 2 users not shown)
Line 12: Line 12:
**The ability to have a lock on a review requires the implementation of some kind of auto-unlock feature. If a user never unlocks a review, his/her teammates still need to be able to modify the review.
**The ability to have a lock on a review requires the implementation of some kind of auto-unlock feature. If a user never unlocks a review, his/her teammates still need to be able to modify the review.
*** We should be able to use the “updated at” field to check if the lock has been held for too long and needs to be released.
*** We should be able to use the “updated at” field to check if the lock has been held for too long and needs to be released.
== More on Locks ==
The locking solution we added works as a general locking solution. It adds a new table in the database called locks which create a mapping between a user and a resource. This database change does not force a lock on the resource. Just because there exists a lock between some resource and some user, does not mean that other users cannot edit that resource. The actual prevention of edits, be it redirecting or preventing access to controller methods, is the responsibility of you, the programmer. This class just provides an easy interface to facilitate that behavior.
=== Database Changes ===
Locks created the following changes:
* locks
** timeout_period
** created_at
** updated_at
** user_id
** lockable_id
** lockable_type
=== Code Changes ===
[[File:E1973_lock_uml.png]]
=== How to implement ===
Whichever model needs to be able to be locked must include this line:
include Lockable
See app/models/response.rb
To check to see if a resource is locked, use
resource = Lock.get_lock(resource, user, timeout_period)
If the resource is nil, it has been locked. If it's not nil, the given user owns the lock over the current resource.
See app/controllers/response_controller.rb#edit
To unlock a resource after it is done being used, use
Lock.release_lock(resource)
See app/controllers/lock_controller.rb#release_lock
To check to see if a lock exists between a user and a resource, use
Lock.lock_between?(resource, user)
See app/controllers/response_controller.rb#update
Because locks can time out, if user1 makes changes and stalls on a page, user2 could get the lock, make edits, and release it. If that's the case, we may not want to keep user1's changes. The way to check for that scenario is by seeing if the user still has a lock on this object.
=== About lock timeouts ===
Lock.get_lock takes a timeout_period. Timeout_period minutes after a user gets a lock, any user who calls get_lock on a resource will acquire a lock.
As the code stands, you MUST include a timeout period if you wish to get a lock. The rationale being that permanently preventing access to a resource is a heavy price for forgetting to unlock a resource. If you wish to do away with this feature, you will need to add the code yourself. (Perhaps using -1 for no time limit). Though I would heavily recommend using the timeout feature.


== Changes to Code ==
== Changes to Code ==
* review_response_map.rb (migration required)
* review_response_map.rb (migration required)
** Field - reviewer_is_team: boolean
** Field - reviewer_is_team: boolean
* review_mapping_controller.rb - update the following methods to use AssignmentTeam as well as AssignmentParticipant as the reviewer
  def after_initialize
** automatic_review_mapping()
    # If an assignment supports team reviews, it is marked in each mapping
** add_calibration()
    reviewer_is_team = assignment.reviewer_is_team
** assign_reviewer_dynamically()
  end
** get_reviewer()
* assignment.rb (migration required)
* assignment.rb (migration required)
** Field - has_team_reviews: boolean
** Field - has_team_reviews: boolean
* assignment_controller.rb
* assignments/edit/_review_strategy.html.erb - added check box for has_team_reviews
** update new() and create() methods to handle new field has_team_reviews
<tr>
* assignment ui files - add check box for has_team_reviews
    <td id='reviewer_is_team'>
      <input name="assignment_form[assignment][reviewer_is_team]" type="hidden" value="false"/>
      <%= check_box_tag('assignment_form[assignment][reviewer_is_team]', 'true', @assignment_form.assignment.reviewer_is_team) %>
      <%= label_tag('assignment_form[assignment][reviewer_is_team]', 'Is Review done by Teams?') %>
      <img src="/assets/info.png" title='You can select whether the reviews should be done by individual students or teams'>
    </td>
  </tr>
* assignment_participant.rb
** Method - get_reviewer
*** Returns the participant's team if the reviews for the assignment are done by teams.
*** Several lines of code treated reviewers explicitly as participants. In order to avoid changing too much functionality, and to go with Dr. Gehringer's request that the changes be polymorphic, we just inserted this method whenever the code treated a participant as a reviewer.
*** Example (review_mapping_controller.rb):
*** Reviewer used to be retrieved by the call to AssignmentParticipant.where. Now, reviewer and participant are treated seperately.
def assign_reviewer_dynamically
    assignment = Assignment.find(params[:assignment_id])
    participant = AssignmentParticipant.where(user_id: params[:reviewer_id], parent_id: assignment.id).first
    reviewer = participant.get_reviewer
    ...
* Added lock.rb, lock_controller.rb, and lockable.rb
* app/views/responses/response.html.erb
** Javascript was added to get locks to be released when the page is exited:
  function release_lock() {
    $.post("../../../lock/release_lock?id=<%= @response.id %>,&type=Response");
  }
  window.onbeforeunload = release_lock;


== Changes Represented in UML ==
== Changes Represented in UML ==
Line 47: Line 110:
== Test Plan ==
== Test Plan ==
=== Rspec ===
=== Rspec ===
Our primary purpose for rspec testing will involve ensuring that we haven't broken any existing functionality.
* Tests were added in response_controller_spec.rb to test that the controller methods properly handle locks and redirect when responses are locked:
Since our new functionality doesn't involve any model/view/controller additions, our tests will be appended to existing rspec tests inside of:
      it 'Does not allow a user to update a response if a lock exists on the response' do
 
        allow(ResponseMap).to receive(:find).with(2).and_return(team_response_map)
* assignments_controller_spec.rb
        allow(Lock).to receive(:get_lock).and_return(nil)
* response_controller_spec.rb
        params = {
* review_mapping_controller_spec.rb
          id: 2,
 
          review: {
The new functionality we need to test should primarily ensure that:
            comments: 'some comments'
          },
          responses: {
            '0' => {score: 98, comment: 'LGTM'}
          },
          isSubmit: 'No'
        }
        session = {user: instructor}
        post :update, params, session
        expect(response).not_to redirect_to('/response/save?id=1&msg=&review%5Bcomments%5D=some+comments')
      end
* Tests were created for lock.rb to ensure that all database functionality is handled properly, locks time out, and locks correctly handle requests from multiple users:
it 'Should create new locks when a user requests them' do
  # smyoder should have a lock on the response for 10 minutes
  expect(Lock.get_lock(@response, @smyoder, 10)).to eq(@response)
  firstLock = Lock.find_by(user: @smyoder, lockable: @response)
  expect(firstLock).not_to be_nil
  # A user with a lock on a resource should be able to renew the lock
  expect(Lock.get_lock(@response, @smyoder, 8)).to eq(@response)
  secondLock = Lock.find_by(user: @smyoder, lockable: @response)
  expect(secondLock).not_to eq(firstLock)
end


* Students on the same team can see each other's review responses
* Since many of expertiza's tests use mocks, several lines in other tests needed to be added since previously un-called methods were now being called:
* No two students can edit a review at the same time
** Example from review_response_map_spec.rb
* Reviews submitted by teams are treated identically to reviews submitted by individuals
allow(participant1).to receive(:get_reviewer).and_return(participant1)


=== UI Testing ===
=== UI Testing ===


Our UI tests aim to capture the following core pieces of functionality:<br>


'''Our UI tests aim to capture the following core pieces of functionality:'''
'''Students on the same team can view/edit the same response:<br>'''
 
 
== Students on the same team can view/edit the same response:<br> ==


''Prerequisites: we use our fixture to ensure that an assignment has been created, and that students 9 and 10 are on a team together. ''


''Prerequisites: instructor6, student7339, student7340, and student7341 exist in the system. This test assumes student7340 and 7341 are on a team.<br><br>''
# Login as student10.
# Navigate to assignments, and click on an assignment.
# Request a new submission to review.
# In the review, leave the comment "Excellent work done!" and click save.
# Logout and login as student 9. Repeat step 2.
# Click View. Notice that the review already says "Excellent work done!".
# Go back to the review and click Edit. Change the message to "Decent work here".
# Logout and login as student 10. Repeat step 2.
# Click View. Notice that the review now says "Decent work here".


  1. Login as instructor6 with password "password".<br>
This test was implemented in the file 'teams_as_reviewers_spec.rb':
  2. Navigate to Manage -> Assignments and click to add a new assignment.<br>
[[File:Team_mates_spec.png]]
  3. Fill in the neccessary fields for rubrics by setting Review to "Peer Review Rubric Example" and Author Feedback to "Area of Focus". Under Review Strategy, check the box "Are Reviewers Teams?". Finally, under Due Dates, set number of rounds to 1. Set due dates such that all are in the future. Make sure to give the assignment a unique name you will remember.<br>
  4. Click back to return to the manage assignments page. Then, click add participants on the assignment you have created. Add student7339 and student7340 to the assignment with the role as participant.<br>
  5. Logout and log in as student7339 (password is "password").<br>
  6. Click on the assignment you created as instructor, and select "Your work". Upload a random link, such as "google.com". Click submit.<br>
  7. Repeat steps 5 through 7, except with student7340 (password is "password").<br>
  8. Logout and login as instructor6. Navigate to Manage -> Assignment and edit the assignment you created previously.<br>
  9. Set the assignment's submission1 date to yesterday and submit. This will allow other students to update the assignment.<br>
  10. Logout and login as student7340.<br>
  11. Now navigate to the assignment, and click "Other's work". Select "Request new review". Click "Begin" on the review.<br>
  12. Fill in dummy values for the review, and click save review.<br>
  13. Logout and login as student7341 (password is "password").<br>
  14. Navigate to the assignment, and click "Other's work". You should be able to see the review response that student7340 was working on. Click on view.<br>
  15. Verify that the information is the same as it entered by student7340.<br>
  16. Click back and then click edit on the review response. Verify that the proper information is prefilled here too. Make a change to one of the response boxes.<br>
  17. Logout and login as student7340. Navigate back to the review response and click "View".<br>
  18. Verify that the changes made by student7341 are present in the response.<br>


=== Manual Testing ===
'''Students cannot edit the response at the same time:<br>'''
''Prerequisites: Same as the above test.''
# Repeat steps 1-4 (inclusive) from the above UI test. However, remain on the edit page.<br>
# Open another browser and navigate to Expertiza. Then, login as student9 in another browser.<br>
# Navigate to the assignment and click "Edit". Verify that you are redirected and unable to edit the review response since student10 is already editing it.<br>


== Students cannot edit the response at the same time: ==
We leave a manual testing section here to cover a scenario we previously planned to add to our feature tests, but realized to be unfeasible. We have functionality that checks that 2 users on the same team cannot edit a response at the same time. However, Expertiza only uses one browser while testing currently. Setting up 2 of them to run at once was deemed beyond the scope of this project.


  1. Repeat steps 1-11 (inclusive) from the above test.<br>
== Relevant Links ==
  2. Open another browser and navigate to Expertiza. Then, login as student7341.<br>
GitHub - https://github.com/TheRazzler/expertiza <br>
  3. Navigate to the assignment and click "Edit". Verify that you are redirected and unable to edit the review response since student7340 is already editing it.<br>
Pull Request - https://github.com/expertiza/expertiza/pull/1643/files <br>
  4. Try clicking "View". Verify that you are unable to view the review response here either.<br>
Demo Video - https://youtu.be/U7MK7HrrmQI
'''Contributors: <br>'''
Spencer Yoder - smyoder@ncsu.edu <br>
Ben Fisher - bjfisher@ncsu.edu <br>

Latest revision as of 16:05, 7 December 2019

Introduction - Purpose & Problem

Currently, reviews of other student’s work can only be performed by individual students in Expertiza, not by groups of students. Since doing reviews together could help students learn more than by doing them alone, it has been requested that reviews must now have the option to be done by teams instead of individual participants. Therefore, there should be an option when creating assignments that allows the creator to select whether the assignment will use team reviewers or individual reviewers. For simplification, we were allowed to assume that the teams that worked on an assignment together would review together. Each participant should be able to make individual changes to the review (while logged in from their account), but these changes should apply to the team’s collective review. This creates an issue where teammates could accidentally overwrite each other’s work if they edit the review at once. Therefore, it has been decided that the review should be locked while one edits it so that only one participant can edit it at once. Locking the review presents its own challenges.

Proposed Solution

  • Modification to Response Map Classes
    • A field should be added to ResponseMap which indicates whether responses are done by teams or by individuals.
  • Modification to Assignment Class
    • A field indicating if the assignment is to be done with team or individuals. This is necessary because part of the suggested requirements is to add a drop down on the review strategy section of the assignment.
  • Locking Solution
    • Research needs to be done as to whether a rails mechanism already exists to facilitate a lock on page edits
    • A solution can be implemented from scratch by storing a flag in the database on the review’s table entry. This would require an additional migration.
    • The ability to have a lock on a review requires the implementation of some kind of auto-unlock feature. If a user never unlocks a review, his/her teammates still need to be able to modify the review.
      • We should be able to use the “updated at” field to check if the lock has been held for too long and needs to be released.

More on Locks

The locking solution we added works as a general locking solution. It adds a new table in the database called locks which create a mapping between a user and a resource. This database change does not force a lock on the resource. Just because there exists a lock between some resource and some user, does not mean that other users cannot edit that resource. The actual prevention of edits, be it redirecting or preventing access to controller methods, is the responsibility of you, the programmer. This class just provides an easy interface to facilitate that behavior.

Database Changes

Locks created the following changes:

  • locks
    • timeout_period
    • created_at
    • updated_at
    • user_id
    • lockable_id
    • lockable_type

Code Changes

How to implement

Whichever model needs to be able to be locked must include this line:

include Lockable

See app/models/response.rb

To check to see if a resource is locked, use

resource = Lock.get_lock(resource, user, timeout_period)

If the resource is nil, it has been locked. If it's not nil, the given user owns the lock over the current resource. See app/controllers/response_controller.rb#edit

To unlock a resource after it is done being used, use

Lock.release_lock(resource)

See app/controllers/lock_controller.rb#release_lock

To check to see if a lock exists between a user and a resource, use

Lock.lock_between?(resource, user)

See app/controllers/response_controller.rb#update Because locks can time out, if user1 makes changes and stalls on a page, user2 could get the lock, make edits, and release it. If that's the case, we may not want to keep user1's changes. The way to check for that scenario is by seeing if the user still has a lock on this object.

About lock timeouts

Lock.get_lock takes a timeout_period. Timeout_period minutes after a user gets a lock, any user who calls get_lock on a resource will acquire a lock.

As the code stands, you MUST include a timeout period if you wish to get a lock. The rationale being that permanently preventing access to a resource is a heavy price for forgetting to unlock a resource. If you wish to do away with this feature, you will need to add the code yourself. (Perhaps using -1 for no time limit). Though I would heavily recommend using the timeout feature.

Changes to Code

  • review_response_map.rb (migration required)
    • Field - reviewer_is_team: boolean
 def after_initialize
   # If an assignment supports team reviews, it is marked in each mapping
   reviewer_is_team = assignment.reviewer_is_team
 end
  • assignment.rb (migration required)
    • Field - has_team_reviews: boolean
  • assignments/edit/_review_strategy.html.erb - added check box for has_team_reviews
     <input name="assignment_form[assignment][reviewer_is_team]" type="hidden" value="false"/>
     <%= check_box_tag('assignment_form[assignment][reviewer_is_team]', 'true', @assignment_form.assignment.reviewer_is_team) %>
     <%= label_tag('assignment_form[assignment][reviewer_is_team]', 'Is Review done by Teams?') %>
     <img src="/assets/info.png" title='You can select whether the reviews should be done by individual students or teams'>
  • assignment_participant.rb
    • Method - get_reviewer
      • Returns the participant's team if the reviews for the assignment are done by teams.
      • Several lines of code treated reviewers explicitly as participants. In order to avoid changing too much functionality, and to go with Dr. Gehringer's request that the changes be polymorphic, we just inserted this method whenever the code treated a participant as a reviewer.
      • Example (review_mapping_controller.rb):
      • Reviewer used to be retrieved by the call to AssignmentParticipant.where. Now, reviewer and participant are treated seperately.

def assign_reviewer_dynamically assignment = Assignment.find(params[:assignment_id]) participant = AssignmentParticipant.where(user_id: params[:reviewer_id], parent_id: assignment.id).first reviewer = participant.get_reviewer ...

  • Added lock.rb, lock_controller.rb, and lockable.rb
  • app/views/responses/response.html.erb
    • Javascript was added to get locks to be released when the page is exited:

function release_lock() { $.post("../../../lock/release_lock?id=<%= @response.id %>,&type=Response"); } window.onbeforeunload = release_lock;

Changes Represented in UML

UI Changes

Assignment Review Strategy

Before

After

Assign Reviewers

Before

After

Test Plan

Rspec

  • Tests were added in response_controller_spec.rb to test that the controller methods properly handle locks and redirect when responses are locked:
     it 'Does not allow a user to update a response if a lock exists on the response' do
       allow(ResponseMap).to receive(:find).with(2).and_return(team_response_map)
       allow(Lock).to receive(:get_lock).and_return(nil)
       params = {
         id: 2,
         review: {
           comments: 'some comments'
         },
         responses: {
           '0' => {score: 98, comment: 'LGTM'}
         },
         isSubmit: 'No'
       }
       session = {user: instructor}
       post :update, params, session
       expect(response).not_to redirect_to('/response/save?id=1&msg=&review%5Bcomments%5D=some+comments')
     end
  • Tests were created for lock.rb to ensure that all database functionality is handled properly, locks time out, and locks correctly handle requests from multiple users:
it 'Should create new locks when a user requests them' do
  # smyoder should have a lock on the response for 10 minutes
  expect(Lock.get_lock(@response, @smyoder, 10)).to eq(@response)
  firstLock = Lock.find_by(user: @smyoder, lockable: @response)
  expect(firstLock).not_to be_nil
  # A user with a lock on a resource should be able to renew the lock
  expect(Lock.get_lock(@response, @smyoder, 8)).to eq(@response)
  secondLock = Lock.find_by(user: @smyoder, lockable: @response)
  expect(secondLock).not_to eq(firstLock)
end
  • Since many of expertiza's tests use mocks, several lines in other tests needed to be added since previously un-called methods were now being called:
    • Example from review_response_map_spec.rb
allow(participant1).to receive(:get_reviewer).and_return(participant1)

UI Testing

Our UI tests aim to capture the following core pieces of functionality:

Students on the same team can view/edit the same response:

Prerequisites: we use our fixture to ensure that an assignment has been created, and that students 9 and 10 are on a team together.

  1. Login as student10.
  2. Navigate to assignments, and click on an assignment.
  3. Request a new submission to review.
  4. In the review, leave the comment "Excellent work done!" and click save.
  5. Logout and login as student 9. Repeat step 2.
  6. Click View. Notice that the review already says "Excellent work done!".
  7. Go back to the review and click Edit. Change the message to "Decent work here".
  8. Logout and login as student 10. Repeat step 2.
  9. Click View. Notice that the review now says "Decent work here".

This test was implemented in the file 'teams_as_reviewers_spec.rb':

Manual Testing

Students cannot edit the response at the same time:
Prerequisites: Same as the above test.

  1. Repeat steps 1-4 (inclusive) from the above UI test. However, remain on the edit page.
  2. Open another browser and navigate to Expertiza. Then, login as student9 in another browser.
  3. Navigate to the assignment and click "Edit". Verify that you are redirected and unable to edit the review response since student10 is already editing it.

We leave a manual testing section here to cover a scenario we previously planned to add to our feature tests, but realized to be unfeasible. We have functionality that checks that 2 users on the same team cannot edit a response at the same time. However, Expertiza only uses one browser while testing currently. Setting up 2 of them to run at once was deemed beyond the scope of this project.

Relevant Links

GitHub - https://github.com/TheRazzler/expertiza
Pull Request - https://github.com/expertiza/expertiza/pull/1643/files
Demo Video - https://youtu.be/U7MK7HrrmQI Contributors:
Spencer Yoder - smyoder@ncsu.edu
Ben Fisher - bjfisher@ncsu.edu