CSC/ECE 517 Fall 2017/E1797 Timestamps for students submission: Difference between revisions
(59 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
==Introduction== | |||
Expertiza is an open source project created using Ruby on Rails. Students can upload and submit their assignments and related work online for grading purposes. Through this project, we aim to provide an interactive and refreshing visual timeline for all the student submissions for each assignment. We provided dynamic functions such as zoom in/zoom out to move left/right and recenter to provide smooth user experience. | |||
===Existing System=== | |||
Currently, there exist various types of submissions that a student can make for an assignment for which timestamps are generated. | |||
*When a student submits links or uploads files as submissions to an assignment in Expertiza, a timestamp is created for the date and time at which each of the submissions was done. | |||
*The student may also be able to give reviews to other works for a particular assignment. These reviews when submitted also have an associated timestamp. | |||
*There also exist timestamps for deadlines that have passed and that are upcoming for an assignment submission or a review to be done. | |||
*For the reviews that a student receives for his work, the student can give feedback to each of the reviews. The submitted feedbacks also get timestamps. | |||
Currently there exists no functionality to view all these submissions and their timestamps in a single, aggregated way. | |||
===Proposed System=== | |||
Our project was to solve this issue by creating a Visualization that helps the student view all the timestamps for his submissions. The goal is to create a Timeline that shows all the timestamps of submitted records and links to the submitted content wherever necessary. The default state of the timeline is a point on the x-axis set to the current date and time. The timeline is interactive and allows the user to zoom in and out to change the viewing scale of the timeline. The user can also scroll in the timeline to move the timeline forward or backward from the current time. After all of this is done, the user can reset the timeline to change his view to the default state. | |||
With this, the student is able to view his entire submission history for an assignment in a convenient way. | |||
==Problem Statement== | ==Problem Statement== | ||
Line 15: | Line 35: | ||
** A Feedback hyperlink that redirects to the feedback by clicking on it | ** A Feedback hyperlink that redirects to the feedback by clicking on it | ||
** Timestamps | ** Timestamps | ||
===Understanding Problem Statement=== | |||
The problem statement states the following issues that had to be resolved. | |||
'''Issue-1:''' | |||
Submission records with timestamps: | |||
A student can submit their work for an assignment using "Your work" button in the respective assignment page. Students have two options to submit their work : | |||
* Giving a hyperlink. | |||
* Uploading a file. | |||
As soon as the user submits any one of these, we needed to show hyperlink or file with the time-stamp on our visualization graph. Also, we needed to provide the submitted '''hyperlink or a link''' to the file on the visualization so that it will be easy for the user to navigate from a single page. | |||
'''Issue-2:''' | |||
Due dates: | |||
There are different due dates for every assignment like Round-1 submission, Round-2 submission, Round-1 review and Round-2 review Due Dates. These are different from submission time stamps because a submission's timestamp depends upon the time at which the user had submitted the work whereas a due date is the deadline date fixed by an instructor. Visualizing them by adding them into the timeline, helps the student to track all due dates in a single graph. | |||
'''Issue-3:''' | |||
Peer Review other's work: | |||
A student needs to review work of different teams during the course of the assignment. As of now in order to view the review, Expertiza requires the user to go to the "other's work" page in the assignment. Instead of this, we want this data to be viewed in our visualization graph. This issue includes a timestamp, link to view review, review round number to be shown in the graph. | |||
'''Note:''' this review is the peer review '''given by this particular student''' to different teams as part of the assignment, '''not the reviews the student received.''' | |||
'''Issue-4:''' | |||
Author's feedback on other's Review | |||
: | |||
A student can give feedback for the review he/she received for a specific assignment. So this information also needs to be included in the graph. We need to show the timestamp and hyperlink to the feedback. It must be noted that the feedback here is not the feedback he got for review given by him/her but the feedback he/she gave for the reviews the had received. | |||
==Program Design== | ==Program Design== | ||
To visualize the timeline graphically we decided to use the vis.js JavaScript library. This library provides various interactive visualization charts (like graphs, networks, timelines, etc) to visualize data in real time. We chose to work on this library because when compared to other popular visualization libraries, vis.js provides the best possible representation of a timeline, one that meets the requirements of our project. To know more about how to make a timeline using vis.js, click [http://visjs.org/docs/timeline/ here]. | |||
The timeline contains a single horizontal axis that is divided into time intervals equally separated from each other. | |||
Let us consider an example where a student makes several submissions to an assignment. The student uploads a hyperlink "https ://www.facebook.com" and an HTML file as submissions. The assignment has several deadlines or due dates. There are due dates for Round 1 and Round 2 submissions for this particular assignment. There are also review deadlines for each of the rounds for the assignment. The student can give a peer review to other students' work on the assignment. The student is able to give feedback to the peer reviews that he received. We have used color coding to differentiate between different kinds of things visualized on the timeline. We have used '''Orange''' color for a round's submission and review deadline and '''Green''' color for all hyperlink submissions, file submissions and '''Cream''' color for feedback, peer review, team review and self review submissions. | |||
So in summary, the following things have to be present on the timeline that are visualized as rectangular boxes on the timeline: | |||
* The submission hyperlink box with the hyperlink | |||
* The file upload box with a link to the uploaded file | |||
* The Round 1 peer review deadline | |||
* The Round 1 submission due date | |||
* The Round 2 peer review deadline | |||
* The Round 2 submission due date | |||
* The Peer Review that the student gave to other students | |||
* The feedback that the student gave to received reviews | |||
* A self-feedback that the student gave to himself | |||
* A team review that the student can give to his teammates | |||
* Additionally, all the rectangular boxed have timestamps that display when the submission was made or the due date of that task | |||
Apart from this, various buttons were also added to better interact with the timeline. These include: | |||
* ''Zoom in'' - To zoom in by magnifying the viewing scale of the timeline | |||
* ''Zoom out'' - To zoom out of the timeline | |||
* ''Move Left'' - To move along the timeline's x-axis. The user can move forward by pressing the button | |||
* ''Move Right'' - To move backward along the x-axis | |||
* '''Recenter''' - Pressing this button helps the user to '''reset the zoom scale''' and the position of the x-axis in a way that all the items appear '''sorted in a single window.''' | |||
A single '''vertical red line''' set to the '''current time''' on the x-axis indicates the current time at which the timeline is being viewed. | |||
The '''percentage of zoom, percentage of window to move right/left''' can be modified as per convenience as mentioned in <script> of zoom buttons mentioned in later section of wiki. | |||
We have added '''hyperlinks to enable quick access to all of the student submitted content'''. For example, the rectangular box that shows the submitted file has a hyperlink that links to the contents of the file. Similarly, the reviews submitted by the student is linked by the hyperlink in the Peer review rectangular box on the timeline. | |||
Finally, after obtaining all the data from the database and the inclusion of all the stated information above to visualizing it in the timeline, the result would be something like this: | |||
[[File:Img1.png]] | |||
When the user selects a particular rectangular box on the timeline by clicking on it, then the line that connects the box to the timeline's x-axis becomes thicker and the color of the box also changes to '''White''' to indicate to the user the current box that is selected. If the user selects the file submission rectangular box (sample.html file), then the timeline would look like this: | |||
[[File:Img2.png]] | |||
==Files Involved== | ==Files Involved== | ||
Line 25: | Line 114: | ||
==Database Tables Involved== | ==Database Tables Involved== | ||
*submission_records | |||
*response_map | |||
*due_dates | |||
*participants | |||
*assignments | |||
*users | |||
*teams | |||
*teams_users | |||
*signed_up_teams | |||
*sign_up_topics | |||
==Implementation== | |||
The code to embed the timeline into the webpage is as follows | |||
< div id="visualization"> | |||
< div class="menu"> | |||
<input id="zoomIn" value="Zoom in" type="button"> | |||
<input id="zoomOut" value="Zoom out" type="button"> | |||
<input id="moveLeft" value="Move left" type="button"> | |||
<input id="moveRight" value="Move right" type="button"> | |||
<input id="Recenter" value="Recenter" type="button"> | |||
< /div> | |||
< /div> | |||
<script type="text/javascript"> | |||
// DOM element where the Timeline will be attached | |||
var container = document.getElementById('visualization'); | |||
// Create a DataSet (allows two way data-binding) | |||
var items = new vis.DataSet(visualization_JSON); | |||
// Configuration for the Timeline | |||
var options = { | |||
zoomMin: 1000 * 60 * 60 * 24, // one day in milliseconds | |||
zoomMax: 1000 * 60 * 60 * 24 * 31 * 12 // about 1 year in milliseconds | |||
}; | |||
// Create a Timeline | |||
var timeline = new vis.Timeline(container, items, options); | |||
</script> | |||
There are several buttons that were inserted into the timeline to allow the user to interact with the timeline. The code for that is | |||
<script> | |||
var visualization_window=timeline.range.getRange(); | |||
function move (percentage) { | |||
var range = timeline.getWindow(); | |||
var interval = range.end - range.start; | |||
timeline.setWindow({ | |||
start: range.start.valueOf() - interval * percentage, | |||
end: range.end.valueOf() - interval * percentage | |||
}); | |||
} | |||
// attach events to the navigation buttons | |||
// zoom percentage in zoomin/zoomout can be adjusted below by passing paramenter. Similar is the case for move left/right along the x-axis | |||
document.getElementById('zoomIn').onclick = function () { timeline.zoomIn( 0.2); }; | |||
document.getElementById('zoomOut').onclick = function () { timeline.zoomOut( 0.2); }; | |||
document.getElementById('moveLeft').onclick = function () { move( 0.2); }; | |||
document.getElementById('moveRight').onclick = function () { move(-0.2); }; | |||
document.getElementById('Recenter').onclick = function () { | |||
var visualization_window_start = new Date(visualization_window.start); | |||
var visualization_window_end = new Date(visualization_window.end); | |||
timeline.setWindow(visualization_window_start, visualization_window_end, { animation: true }); | |||
}; | |||
</script> | |||
The functionality of each button is explained in the Program Design section above. | |||
It is necessary to obtain data from the Expertiza database to JSON format so that it can be processed by the timeline for visualization. After collecting the data from the database, processing it and storing it into a ruby variable, we use the JSON.parse() function to convert that information into JSON objects. To maintain continuity, the process of obtaining data and preprocessing it is explained later in the wiki. The code to convert the variable contents into a JSON object is as follows: | |||
<script> | |||
// converting @visualization_data array to javascript compatible JSON object | |||
var visualization_JSON = JSON.parse('<%=raw @visualization_data.to_json%>'); | |||
var href_JSON = JSON.parse('<%= @href_arr.to_json.html_safe%>') | |||
var temp; | |||
//temp is temporary variable used to generate hyperlinks from content | |||
for(i=0; i<visualization_JSON.length; i++) { | |||
temp=visualization_JSON[i].content.split("<split>"); | |||
if(href_JSON[i]==' ') | |||
visualization_JSON[i].content = temp[0]+"<br>"+temp.slice(1); | |||
else | |||
visualization_JSON[i].content = "<a href="+href_JSON[i]+" target='_blank'><b><u>"+temp[0]+"</u></b></a><br>"+temp.slice(1); | |||
} | |||
</script> | |||
The following code is used to display due dates in the timeline. The types of due dates included are Round submission or Round review due date. | |||
<% @href_arr= Array.new %> | |||
<! -- @href_arr is used to store all the hyperlinks for each visualized object --> | |||
<% @duedates = DueDate.where("parent_id = #{@assignment.id}") | |||
@visualization_data = @duedates.map do |due| | |||
@href_arr.push(""); #empty hyperlink as we do not provide hyperlinks for submissions/reviews | |||
if due.deadline_type_id.eql? 1 | |||
{ :id => due.id, :start=> due.due_at, :className => "submissionDue", :content => "Round "+(due.round.to_s)+"<split>Submission due by "+'<br>'+due.due_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
else | |||
{ :id => due.id, :start=> due.due_at, :className => "reviewDue", :content => "Round "+(due.round.to_s)+"<split>Review due by "+'<br>'+due.due_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
end | |||
%> | |||
Then we need to add submission hyperlinks and files in the timeline. The code for that is | |||
< ! -- display only if submissions are made--> | |||
<% unless @team.nil? | |||
@submissions = SubmissionRecord.find_by_sql"select * from submission_records where assignment_id=#{@assignment.id} and team_id=#{@team.id} | |||
and content NOT IN (select content from submission_records where assignment_id=#{@assignment.id} and team_id=#{@team.id} and UPPER(operation) Like 'REMOVE%')" | |||
@visualization_data += @submissions.map do |submission| | |||
#display_directory_tree(participant, files, true).html_safe | |||
if (submission.operation).eql?('Submit File') | |||
file = submission.content | |||
ret="" | |||
if File.exist?(file) && File.directory?(file) | |||
ret += link_to File.basename(file), :controller => 'submitted_content', :action => 'edit', :id => participant.id, "current_folder[name]" => file | |||
else | |||
ret += "\n " | |||
ret += link_to File.basename(file), :controller => 'submitted_content', | |||
:action => 'download', | |||
:id => @participant.id, | |||
:download => File.basename(file), | |||
"current_folder[name]" => File.dirname(file) | |||
end | |||
@href_arr.push(ret.split('"')[1]) | |||
#only file name instead of entire relative path need to be displayed on timeline. Hence we push the same in content, appending created time to it | |||
{ :id => submission.id, :start=> submission.created_at, :className=> "fileUpload", :content => (submission.content).split('/')[-1]+'<split>'+ | |||
submission.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
else | |||
@href_arr.push(submission.content) | |||
{ :id => submission.id, :start=> submission.created_at, :className=> "hyperlinkUpload" ,:content => submission.content+'<split>'+ | |||
submission.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
end | |||
end %> | |||
'''Explanation:''' The following code fetches submission records of a student for a particular assignment from the '''submission_records''' table. Then after checking if the submission exists and when the type is a file, a hyperlink to the file's location path is obtained and pushed into the JSON. The same is done for a submission with the type Hyperlink. | |||
Then to get the peer reviews, self-reviews, feedback and team reviews, the following code is used. | |||
<! -- Reviews not yet started --> | |||
<% unless @review_mappings.nil? | |||
@review_mappings.each do |review_mapping_iterator| | |||
@response_values = Response.where(:map_id => review_mapping_iterator.id) | |||
@visualization_data += @response_values.map do |response_value_iterator| | |||
if review_mapping_iterator.type=="ReviewResponseMap" | |||
review_mapping = ResponseMap.find(review_mapping_iterator.reviewed_object_id) | |||
participant = AssignmentTeam.get_first_member(review_mapping_iterator.reviewee_id) | |||
topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id) | |||
if !topic_id.nil? | |||
if SignUpTopic.find(topic_id).topic_identifier != '' | |||
@topic_name=SignUpTopic.find(topic_id).topic_identifier+": "+SignUpTopic.find(topic_id).topic_name | |||
else | |||
@topic_name=SignUpTopic.find(topic_id).topic_name | |||
end | |||
end | |||
unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? | |||
@href_arr.push("../response/view?id="+response_value_iterator.id.to_s) | |||
{ :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "review", :content => "Peer Review - | |||
Round "+response_value_iterator.round.to_s+"<split> Review for: #{@topic_name}"+'<br>'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
elsif review_mapping_iterator.type=="SelfReviewResponseMap" | |||
unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? | |||
@href_arr.push("../response/view?id="+response_value_iterator.id.to_s) | |||
{ :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "selfReview", :content => "Self Feedback - | |||
Round "+response_value_iterator.round.to_s+"<split>Self Feedback"+'<br>'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
elsif review_mapping_iterator.type=="TeammateReviewResponseMap" | |||
unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? | |||
reviewee = ResponseMap.where(:reviewer_id => "#{review_mapping_iterator.reviewer_id}", :id =>"#{review_mapping_iterator.id}").pluck(:reviewee_id) | |||
puts reviewee.to_s+" "+review_mapping_iterator.reviewer_id.to_s+" "+review_mapping_iterator.id.to_s | |||
user_id = Participant.where(:id=> "#{reviewee[0]}").pluck(:user_id) | |||
reviewee_name = User.where(:id=>"#{user_id[0]}").pluck(:name) | |||
@href_arr.push("../response/view?id="+response_value_iterator.id.to_s) | |||
{ :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "teamReview", :content => "Team Review - | |||
Round "+response_value_iterator.round.to_s+"<split>Team review for #{reviewee_name[0]}"+'<br>'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
else | |||
unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? | |||
@href_arr.push("../response/view?id="+response_value_iterator.id.to_s) | |||
{ :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "feedback", :content => "Feedback - | |||
Round "+response_value_iterator.round.to_s+"<split>Feedback"+'<br>'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } | |||
end | |||
end | |||
end | |||
end | |||
end %> | |||
==Test Plan== | ==Test Plan== | ||
===Automated test using RSpec=== | |||
Resources - | |||
* [http://rspec.info/ RSpec] | |||
* [https://github.com/thoughtbot/factory_girl Factory Girl ruby gem] | |||
A new file with the name <b>timestamps_for_students_submissions_spec.rb</b> file was created in <b>spec/features</b> folder with various test cases to test the changes. | |||
===Testing from UI=== | |||
Testing the project using the User Interface. | |||
*Login as an instructor, go to manage assignments-> select an assignment-> add students to assignment->update duedates. | |||
*Impersonate as one of student -> navigate to the particular assignment edited in above step. | |||
*You shall see a timeline with duedates | |||
*Click on your work, submit hyperlink/files, same will be displayed in that particular assignment home page(navigate to previous page) | |||
*Review teammates work/ give a peer review/ submit a self review/ submit feedback to review received, same will be reflected in respective assignment home page along with a hyperlink to the particular review given. | |||
*The submission along with the timestamps for each submission along with hyperlinks to each of student's work is displayed in timeline. | |||
*One can test for the Edge cases mentioned above too. | |||
We have written tests for 3 scenarios | |||
* '''Scenario 1: Testing whether deadlines are visible on the graph:''' | |||
We created a dummy assignment with associated deadline in “before” statement. The code for that is: | |||
before(:each) do | |||
create(:assignment, name: "E1797-Test", directory_path: 'test_assignment') | |||
create_list(:participant, 3) | |||
create(:assignment_node) | |||
create(:deadline_type, name: "submission") | |||
create(:deadline_type, name: "review") | |||
create(:deadline_type, name: "metareview") | |||
create(:deadline_type, name: "drop_topic") | |||
create(:deadline_type, name: "team_formation") | |||
create(:deadline_right) | |||
create(:deadline_right, name: 'Late') | |||
create(:deadline_right, name: 'OK') | |||
create(:assignment_due_date, deadline_type: DeadlineType.where(name: 'review').first, due_at: '2200-12-22T22:33:23.000-05:00') | |||
login_as("student2065") | |||
visit '/student_task/list' | |||
end | |||
Then, in the test case we tested whether the deadline is present on the graph. | |||
The RSpec Feature testing code is : | |||
it 'displays review due dates along with its timestamps' do | |||
# checks whether the UI has above given deadline | |||
click_link "E1797-Test" | |||
page.html.should include('2200-12-22T22:33:23.000-05:00') | |||
end | |||
* '''Scenario 2: Testing whether submitted linked is visible on the graph:''' | |||
Since we already created a assignment in the “before” statement In this particular test case, we submitted the work for an assignment in “Your Work” tab and checked whether this link is present in the graph. The RSpec code is as follows: | |||
it 'displays submitted hyperlink along with timestamp' do | |||
# submit a generic link for this assignment | |||
click_link "E1797-Test" | |||
click_link "Your work" | |||
fill_in "submission", with: "http://www.google.com" | |||
click_button "Upload link" | |||
# expect the same link to be present in our graph | |||
page.all('a', text: 'Assignments')[1].click | |||
click_link "E1797-Test" | |||
page.html.should include('https://www.google.com') | |||
end | |||
* '''Scenario 3: Testing whether submitted file is visible on the graph:''' | |||
In this particular test case a file as submission for an assignment was uploaded. After this. it is checked whether this file is present in the graph. | |||
it 'displays submitted file along with timestamp' do | |||
# submit a generic file for this assignment | |||
click_link "E1797-Test" | |||
click_link "Your work" | |||
file_path = Rails.root + "spec/features/timestamp_students_submissions_spec.rb" | |||
attach_file('uploaded_file', file_path) | |||
click_on 'Upload file' | |||
# expect the same file to be present in our graph | |||
page.all('a', text: 'Assignments')[1].click | |||
click_link "E1797-Test" | |||
page.html.should include('timestamp_students_submissions_spec.rb') | |||
end | |||
==Edge Cases== | |||
'''Timeline behavior when the student opens the view page of a newly created assignment''' | |||
* When the user has not made any submissions, reviews or feedbacks to reviews to the assignment, the timeline must only display the due dates of the assignment. | |||
'''Timeline behavior when student has not joined any team and makes submissions''' | |||
* When a student who is not part of any team makes a submission, he is assigned a team_ID by Expertiza and all submissions made by him are linked to that ID. So only those submissions will be displayed on the timeline. | |||
'''Timeline behavior when the student joins a team, what happens to the submissions he made before joining the team''' | |||
* When he joins a team and he receives a new team_ID, any submissions made hereafter will be made under the new team_ID and all previous submissions made by the student will not be shown on the timeline(this is how Expertiza assigns team_IDs and submissions- the same is reflected in 'your work' section of a user's profile). Only the user submissions made after he joins the team is shown on the timeline. | |||
'''Timeline behavior when there is no topic name for a given assignment''' | |||
* Sometimes topics in assignment are not named(eg program 2 - car rental app). In the peer review submission rectangular box displayed on the timeline after the student submits a peer review, instead of showing the label "Review for [topic name]", the label says "Review". | |||
'''Timeline behavior when a submitted hyperlink is removed''' | |||
* When a submitted hyperlink is removed, the submission must not be displayed on the timeline any more. | |||
'''A submission must be made before a peer review can be given''' | |||
* This condition holds even if the deadline has already passed. | |||
==Future modifications== | |||
We can also include icons that are embedded into the rectangles. They act as visual aids to help the user quickly recognize the category of the box. We propose a design that would look something like this: | |||
[[File:S3.png]] | |||
===References=== | |||
#[https://github.com/expertiza/expertiza Expertiza on GitHub] | |||
#[http://expertiza.ncsu.edu/ The live Expertiza website] | |||
#[http://wiki.expertiza.ncsu.edu/index.php/Expertiza_documentation Expertiza project documentation wiki] | |||
#[https://relishapp.com/rspec Rspec Documentation] | |||
#[http://visjs.org/docs/timeline/ Vis.js Documentation for Timeline] | |||
#[https://github.com/expertiza/expertiza/pull/1126 Github pull request submitted] | |||
#[https://github.com/ShyamKatta/expertiza/tree/E1797/ Github - expertiza forked repository] |
Latest revision as of 11:49, 6 December 2017
Introduction
Expertiza is an open source project created using Ruby on Rails. Students can upload and submit their assignments and related work online for grading purposes. Through this project, we aim to provide an interactive and refreshing visual timeline for all the student submissions for each assignment. We provided dynamic functions such as zoom in/zoom out to move left/right and recenter to provide smooth user experience.
Existing System
Currently, there exist various types of submissions that a student can make for an assignment for which timestamps are generated.
- When a student submits links or uploads files as submissions to an assignment in Expertiza, a timestamp is created for the date and time at which each of the submissions was done.
- The student may also be able to give reviews to other works for a particular assignment. These reviews when submitted also have an associated timestamp.
- There also exist timestamps for deadlines that have passed and that are upcoming for an assignment submission or a review to be done.
- For the reviews that a student receives for his work, the student can give feedback to each of the reviews. The submitted feedbacks also get timestamps.
Currently there exists no functionality to view all these submissions and their timestamps in a single, aggregated way.
Proposed System
Our project was to solve this issue by creating a Visualization that helps the student view all the timestamps for his submissions. The goal is to create a Timeline that shows all the timestamps of submitted records and links to the submitted content wherever necessary. The default state of the timeline is a point on the x-axis set to the current date and time. The timeline is interactive and allows the user to zoom in and out to change the viewing scale of the timeline. The user can also scroll in the timeline to move the timeline forward or backward from the current time. After all of this is done, the user can reset the timeline to change his view to the default state.
With this, the student is able to view his entire submission history for an assignment in a convenient way.
Problem Statement
In Expertiza, it is possible for the instructor to view the submission records of a particular student. However, there is no way for students to check the history of their submission records. In this project, we are required to keep track of students’ activities and visualize them on their end by using a timeline chart.
What needs to be visualized on the timeline:
- Hyperlink submission record with timestamps
- File upload record with timestamps
- Due dates
- Visualization of Peer review of others works, which includes:
- A Review hyperlink that redirects to the review by clicking on it
- The Round number (To be displayed only if the assignment has multiple rounds)
- Timestamps
- Visualization of Author feedback on others review, which includes:
- A Feedback hyperlink that redirects to the feedback by clicking on it
- Timestamps
Understanding Problem Statement
The problem statement states the following issues that had to be resolved.
Issue-1: Submission records with timestamps:
A student can submit their work for an assignment using "Your work" button in the respective assignment page. Students have two options to submit their work :
- Giving a hyperlink.
- Uploading a file.
As soon as the user submits any one of these, we needed to show hyperlink or file with the time-stamp on our visualization graph. Also, we needed to provide the submitted hyperlink or a link to the file on the visualization so that it will be easy for the user to navigate from a single page.
Issue-2: Due dates:
There are different due dates for every assignment like Round-1 submission, Round-2 submission, Round-1 review and Round-2 review Due Dates. These are different from submission time stamps because a submission's timestamp depends upon the time at which the user had submitted the work whereas a due date is the deadline date fixed by an instructor. Visualizing them by adding them into the timeline, helps the student to track all due dates in a single graph.
Issue-3: Peer Review other's work:
A student needs to review work of different teams during the course of the assignment. As of now in order to view the review, Expertiza requires the user to go to the "other's work" page in the assignment. Instead of this, we want this data to be viewed in our visualization graph. This issue includes a timestamp, link to view review, review round number to be shown in the graph. Note: this review is the peer review given by this particular student to different teams as part of the assignment, not the reviews the student received.
Issue-4: Author's feedback on other's Review
A student can give feedback for the review he/she received for a specific assignment. So this information also needs to be included in the graph. We need to show the timestamp and hyperlink to the feedback. It must be noted that the feedback here is not the feedback he got for review given by him/her but the feedback he/she gave for the reviews the had received.
Program Design
To visualize the timeline graphically we decided to use the vis.js JavaScript library. This library provides various interactive visualization charts (like graphs, networks, timelines, etc) to visualize data in real time. We chose to work on this library because when compared to other popular visualization libraries, vis.js provides the best possible representation of a timeline, one that meets the requirements of our project. To know more about how to make a timeline using vis.js, click here.
The timeline contains a single horizontal axis that is divided into time intervals equally separated from each other.
Let us consider an example where a student makes several submissions to an assignment. The student uploads a hyperlink "https ://www.facebook.com" and an HTML file as submissions. The assignment has several deadlines or due dates. There are due dates for Round 1 and Round 2 submissions for this particular assignment. There are also review deadlines for each of the rounds for the assignment. The student can give a peer review to other students' work on the assignment. The student is able to give feedback to the peer reviews that he received. We have used color coding to differentiate between different kinds of things visualized on the timeline. We have used Orange color for a round's submission and review deadline and Green color for all hyperlink submissions, file submissions and Cream color for feedback, peer review, team review and self review submissions.
So in summary, the following things have to be present on the timeline that are visualized as rectangular boxes on the timeline:
- The submission hyperlink box with the hyperlink
- The file upload box with a link to the uploaded file
- The Round 1 peer review deadline
- The Round 1 submission due date
- The Round 2 peer review deadline
- The Round 2 submission due date
- The Peer Review that the student gave to other students
- The feedback that the student gave to received reviews
- A self-feedback that the student gave to himself
- A team review that the student can give to his teammates
- Additionally, all the rectangular boxed have timestamps that display when the submission was made or the due date of that task
Apart from this, various buttons were also added to better interact with the timeline. These include:
- Zoom in - To zoom in by magnifying the viewing scale of the timeline
- Zoom out - To zoom out of the timeline
- Move Left - To move along the timeline's x-axis. The user can move forward by pressing the button
- Move Right - To move backward along the x-axis
- Recenter - Pressing this button helps the user to reset the zoom scale and the position of the x-axis in a way that all the items appear sorted in a single window.
A single vertical red line set to the current time on the x-axis indicates the current time at which the timeline is being viewed.
The percentage of zoom, percentage of window to move right/left can be modified as per convenience as mentioned in <script> of zoom buttons mentioned in later section of wiki.
We have added hyperlinks to enable quick access to all of the student submitted content. For example, the rectangular box that shows the submitted file has a hyperlink that links to the contents of the file. Similarly, the reviews submitted by the student is linked by the hyperlink in the Peer review rectangular box on the timeline.
Finally, after obtaining all the data from the database and the inclusion of all the stated information above to visualizing it in the timeline, the result would be something like this:
When the user selects a particular rectangular box on the timeline by clicking on it, then the line that connects the box to the timeline's x-axis becomes thicker and the color of the box also changes to White to indicate to the user the current box that is selected. If the user selects the file submission rectangular box (sample.html file), then the timeline would look like this:
Files Involved
- app/controllers/submission_records_controller.rb
- app/models/submission_record.rb
- app/views/student_task/list.html.erb
Database Tables Involved
- submission_records
- response_map
- due_dates
- participants
- assignments
- users
- teams
- teams_users
- signed_up_teams
- sign_up_topics
Implementation
The code to embed the timeline into the webpage is as follows
< div id="visualization"> < div class="menu"> <input id="zoomIn" value="Zoom in" type="button"> <input id="zoomOut" value="Zoom out" type="button"> <input id="moveLeft" value="Move left" type="button"> <input id="moveRight" value="Move right" type="button"> <input id="Recenter" value="Recenter" type="button"> < /div> < /div> <script type="text/javascript"> // DOM element where the Timeline will be attached var container = document.getElementById('visualization'); // Create a DataSet (allows two way data-binding) var items = new vis.DataSet(visualization_JSON); // Configuration for the Timeline var options = { zoomMin: 1000 * 60 * 60 * 24, // one day in milliseconds zoomMax: 1000 * 60 * 60 * 24 * 31 * 12 // about 1 year in milliseconds }; // Create a Timeline var timeline = new vis.Timeline(container, items, options); </script>
There are several buttons that were inserted into the timeline to allow the user to interact with the timeline. The code for that is
<script> var visualization_window=timeline.range.getRange(); function move (percentage) { var range = timeline.getWindow(); var interval = range.end - range.start; timeline.setWindow({ start: range.start.valueOf() - interval * percentage, end: range.end.valueOf() - interval * percentage }); } // attach events to the navigation buttons // zoom percentage in zoomin/zoomout can be adjusted below by passing paramenter. Similar is the case for move left/right along the x-axis document.getElementById('zoomIn').onclick = function () { timeline.zoomIn( 0.2); }; document.getElementById('zoomOut').onclick = function () { timeline.zoomOut( 0.2); }; document.getElementById('moveLeft').onclick = function () { move( 0.2); }; document.getElementById('moveRight').onclick = function () { move(-0.2); }; document.getElementById('Recenter').onclick = function () { var visualization_window_start = new Date(visualization_window.start); var visualization_window_end = new Date(visualization_window.end); timeline.setWindow(visualization_window_start, visualization_window_end, { animation: true }); }; </script>
The functionality of each button is explained in the Program Design section above.
It is necessary to obtain data from the Expertiza database to JSON format so that it can be processed by the timeline for visualization. After collecting the data from the database, processing it and storing it into a ruby variable, we use the JSON.parse() function to convert that information into JSON objects. To maintain continuity, the process of obtaining data and preprocessing it is explained later in the wiki. The code to convert the variable contents into a JSON object is as follows:
<script> // converting @visualization_data array to javascript compatible JSON object var visualization_JSON = JSON.parse('<%=raw @visualization_data.to_json%>'); var href_JSON = JSON.parse('<%= @href_arr.to_json.html_safe%>') var temp; //temp is temporary variable used to generate hyperlinks from content for(i=0; i<visualization_JSON.length; i++) { temp=visualization_JSON[i].content.split("<split>"); if(href_JSON[i]==' ') visualization_JSON[i].content = temp[0]+"
"+temp.slice(1); else visualization_JSON[i].content = "<a href="+href_JSON[i]+" target='_blank'>"+temp[0]+"</a>
"+temp.slice(1); } </script>
The following code is used to display due dates in the timeline. The types of due dates included are Round submission or Round review due date.
<% @href_arr= Array.new %> <! -- @href_arr is used to store all the hyperlinks for each visualized object --> <% @duedates = DueDate.where("parent_id = #{@assignment.id}") @visualization_data = @duedates.map do |due| @href_arr.push(""); #empty hyperlink as we do not provide hyperlinks for submissions/reviews if due.deadline_type_id.eql? 1 { :id => due.id, :start=> due.due_at, :className => "submissionDue", :content => "Round "+(due.round.to_s)+"<split>Submission due by "+'
'+due.due_at.strftime("%m/%d/%Y at %I:%M %p") } else { :id => due.id, :start=> due.due_at, :className => "reviewDue", :content => "Round "+(due.round.to_s)+"<split>Review due by "+'
'+due.due_at.strftime("%m/%d/%Y at %I:%M %p") } end end %>
Then we need to add submission hyperlinks and files in the timeline. The code for that is
< ! -- display only if submissions are made--> <% unless @team.nil? @submissions = SubmissionRecord.find_by_sql"select * from submission_records where assignment_id=#{@assignment.id} and team_id=#{@team.id} and content NOT IN (select content from submission_records where assignment_id=#{@assignment.id} and team_id=#{@team.id} and UPPER(operation) Like 'REMOVE%')" @visualization_data += @submissions.map do |submission| #display_directory_tree(participant, files, true).html_safe if (submission.operation).eql?('Submit File') file = submission.content ret="" if File.exist?(file) && File.directory?(file) ret += link_to File.basename(file), :controller => 'submitted_content', :action => 'edit', :id => participant.id, "current_folder[name]" => file else ret += "\n " ret += link_to File.basename(file), :controller => 'submitted_content', :action => 'download', :id => @participant.id, :download => File.basename(file), "current_folder[name]" => File.dirname(file) end @href_arr.push(ret.split('"')[1]) #only file name instead of entire relative path need to be displayed on timeline. Hence we push the same in content, appending created time to it { :id => submission.id, :start=> submission.created_at, :className=> "fileUpload", :content => (submission.content).split('/')[-1]+'<split>'+ submission.created_at.strftime("%m/%d/%Y at %I:%M %p") } else @href_arr.push(submission.content) { :id => submission.id, :start=> submission.created_at, :className=> "hyperlinkUpload" ,:content => submission.content+'<split>'+ submission.created_at.strftime("%m/%d/%Y at %I:%M %p") } end end end %>
Explanation: The following code fetches submission records of a student for a particular assignment from the submission_records table. Then after checking if the submission exists and when the type is a file, a hyperlink to the file's location path is obtained and pushed into the JSON. The same is done for a submission with the type Hyperlink.
Then to get the peer reviews, self-reviews, feedback and team reviews, the following code is used.
<! -- Reviews not yet started --> <% unless @review_mappings.nil? @review_mappings.each do |review_mapping_iterator| @response_values = Response.where(:map_id => review_mapping_iterator.id) @visualization_data += @response_values.map do |response_value_iterator| if review_mapping_iterator.type=="ReviewResponseMap" review_mapping = ResponseMap.find(review_mapping_iterator.reviewed_object_id) participant = AssignmentTeam.get_first_member(review_mapping_iterator.reviewee_id) topic_id = SignedUpTeam.topic_id(participant.parent_id, participant.user_id) if !topic_id.nil? if SignUpTopic.find(topic_id).topic_identifier != @topic_name=SignUpTopic.find(topic_id).topic_identifier+": "+SignUpTopic.find(topic_id).topic_name else @topic_name=SignUpTopic.find(topic_id).topic_name end end unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? @href_arr.push("../response/view?id="+response_value_iterator.id.to_s) { :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "review", :content => "Peer Review - Round "+response_value_iterator.round.to_s+"<split> Review for: #{@topic_name}"+'
'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } end elsif review_mapping_iterator.type=="SelfReviewResponseMap" unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? @href_arr.push("../response/view?id="+response_value_iterator.id.to_s) { :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "selfReview", :content => "Self Feedback - Round "+response_value_iterator.round.to_s+"<split>Self Feedback"+'
'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } end elsif review_mapping_iterator.type=="TeammateReviewResponseMap" unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? reviewee = ResponseMap.where(:reviewer_id => "#{review_mapping_iterator.reviewer_id}", :id =>"#{review_mapping_iterator.id}").pluck(:reviewee_id) puts reviewee.to_s+" "+review_mapping_iterator.reviewer_id.to_s+" "+review_mapping_iterator.id.to_s user_id = Participant.where(:id=> "#{reviewee[0]}").pluck(:user_id) reviewee_name = User.where(:id=>"#{user_id[0]}").pluck(:name) @href_arr.push("../response/view?id="+response_value_iterator.id.to_s) { :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "teamReview", :content => "Team Review - Round "+response_value_iterator.round.to_s+"<split>Team review for #{reviewee_name[0]}"+'
'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } end else unless response_value_iterator.nil? and response_value_iterator.is_submitted.zero? @href_arr.push("../response/view?id="+response_value_iterator.id.to_s) { :id => response_value_iterator.id, :start=> response_value_iterator.created_at, :className => "feedback", :content => "Feedback - Round "+response_value_iterator.round.to_s+"<split>Feedback"+'
'+response_value_iterator.created_at.strftime("%m/%d/%Y at %I:%M %p") } end end end end end %>
Test Plan
Automated test using RSpec
Resources -
A new file with the name timestamps_for_students_submissions_spec.rb file was created in spec/features folder with various test cases to test the changes.
Testing from UI
Testing the project using the User Interface.
- Login as an instructor, go to manage assignments-> select an assignment-> add students to assignment->update duedates.
- Impersonate as one of student -> navigate to the particular assignment edited in above step.
- You shall see a timeline with duedates
- Click on your work, submit hyperlink/files, same will be displayed in that particular assignment home page(navigate to previous page)
- Review teammates work/ give a peer review/ submit a self review/ submit feedback to review received, same will be reflected in respective assignment home page along with a hyperlink to the particular review given.
- The submission along with the timestamps for each submission along with hyperlinks to each of student's work is displayed in timeline.
- One can test for the Edge cases mentioned above too.
We have written tests for 3 scenarios
- Scenario 1: Testing whether deadlines are visible on the graph:
We created a dummy assignment with associated deadline in “before” statement. The code for that is:
before(:each) do create(:assignment, name: "E1797-Test", directory_path: 'test_assignment') create_list(:participant, 3) create(:assignment_node) create(:deadline_type, name: "submission") create(:deadline_type, name: "review") create(:deadline_type, name: "metareview") create(:deadline_type, name: "drop_topic") create(:deadline_type, name: "team_formation") create(:deadline_right) create(:deadline_right, name: 'Late') create(:deadline_right, name: 'OK') create(:assignment_due_date, deadline_type: DeadlineType.where(name: 'review').first, due_at: '2200-12-22T22:33:23.000-05:00') login_as("student2065") visit '/student_task/list' end
Then, in the test case we tested whether the deadline is present on the graph. The RSpec Feature testing code is :
it 'displays review due dates along with its timestamps' do # checks whether the UI has above given deadline click_link "E1797-Test" page.html.should include('2200-12-22T22:33:23.000-05:00') end
- Scenario 2: Testing whether submitted linked is visible on the graph:
Since we already created a assignment in the “before” statement In this particular test case, we submitted the work for an assignment in “Your Work” tab and checked whether this link is present in the graph. The RSpec code is as follows:
it 'displays submitted hyperlink along with timestamp' do # submit a generic link for this assignment click_link "E1797-Test" click_link "Your work" fill_in "submission", with: "http://www.google.com" click_button "Upload link" # expect the same link to be present in our graph page.all('a', text: 'Assignments')[1].click click_link "E1797-Test" page.html.should include('https://www.google.com') end
- Scenario 3: Testing whether submitted file is visible on the graph:
In this particular test case a file as submission for an assignment was uploaded. After this. it is checked whether this file is present in the graph.
it 'displays submitted file along with timestamp' do # submit a generic file for this assignment click_link "E1797-Test" click_link "Your work" file_path = Rails.root + "spec/features/timestamp_students_submissions_spec.rb" attach_file('uploaded_file', file_path) click_on 'Upload file' # expect the same file to be present in our graph page.all('a', text: 'Assignments')[1].click click_link "E1797-Test" page.html.should include('timestamp_students_submissions_spec.rb') end
Edge Cases
Timeline behavior when the student opens the view page of a newly created assignment
- When the user has not made any submissions, reviews or feedbacks to reviews to the assignment, the timeline must only display the due dates of the assignment.
Timeline behavior when student has not joined any team and makes submissions
- When a student who is not part of any team makes a submission, he is assigned a team_ID by Expertiza and all submissions made by him are linked to that ID. So only those submissions will be displayed on the timeline.
Timeline behavior when the student joins a team, what happens to the submissions he made before joining the team
- When he joins a team and he receives a new team_ID, any submissions made hereafter will be made under the new team_ID and all previous submissions made by the student will not be shown on the timeline(this is how Expertiza assigns team_IDs and submissions- the same is reflected in 'your work' section of a user's profile). Only the user submissions made after he joins the team is shown on the timeline.
Timeline behavior when there is no topic name for a given assignment
- Sometimes topics in assignment are not named(eg program 2 - car rental app). In the peer review submission rectangular box displayed on the timeline after the student submits a peer review, instead of showing the label "Review for [topic name]", the label says "Review".
Timeline behavior when a submitted hyperlink is removed
- When a submitted hyperlink is removed, the submission must not be displayed on the timeline any more.
A submission must be made before a peer review can be given
- This condition holds even if the deadline has already passed.
Future modifications
We can also include icons that are embedded into the rectangles. They act as visual aids to help the user quickly recognize the category of the box. We propose a design that would look something like this: