Skip to content

Commit 5b97e13

Browse files
committed
Add difference with model solution
1 parent 9d31bb1 commit 5b97e13

File tree

4 files changed

+84
-3
lines changed

4 files changed

+84
-3
lines changed

app/controllers/submissions_controller.rb

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class SubmissionsController < ApplicationController
77
before_action :get_course_and_exercise
88

99
# Manually checked for #show and index
10-
skip_authorization_check only: [:show, :index]
10+
skip_authorization_check only: [:show, :index, :difference_with_solution]
1111

1212
def index
1313
respond_to do |format|
@@ -195,6 +195,41 @@ def update_by_exercise
195195
redirect_to exercise_path(@exercise), notice: 'Reruns scheduled'
196196
end
197197

198+
def difference_with_solution
199+
respond_access_denied unless current_user.administrator?
200+
@course ||= @submission.course
201+
@exercise ||= @submission.exercise
202+
@organization = @course.organization
203+
add_course_breadcrumb
204+
add_exercise_breadcrumb
205+
add_submission_breadcrumb
206+
add_breadcrumb 'Difference with model solution'
207+
208+
submission_files = SourceFileList.for_submission(@submission)
209+
solution_files = SourceFileList.for_solution(@exercise.solution)
210+
files_in_list = Set.new
211+
@files = []
212+
submission_files.each do |file|
213+
# TODO: In some exercises files may be named differently. Some kind of
214+
# similarity metric would be nice here
215+
model = solution_files.find { |solution_file| file.path == solution_file.path}
216+
@files << {
217+
path: file.path,
218+
submission_contents: file.contents,
219+
model_contents: (model.nil? ? '' : model.contents)
220+
}
221+
files_in_list << file.path
222+
end
223+
solution_files.each do |file|
224+
next if files_in_list.include?(file.path)
225+
@files << {
226+
path: file.path,
227+
submission_contents: '',
228+
model_contents: model.contents
229+
}
230+
end
231+
end
232+
198233
private
199234

200235
def course_transaction
@@ -205,8 +240,9 @@ def course_transaction
205240

206241
# Ugly manual access control :/
207242
def get_course_and_exercise
208-
if params[:id]
209-
@submission = Submission.find(params[:id])
243+
submission_id = params[:id] || params[:submission_id]
244+
if submission_id
245+
@submission = Submission.find(submission_id)
210246
authorize! :read, @submission
211247
@course = @submission.course
212248
@exercise = @submission.exercise

app/views/submissions/_submission_details.html.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565

6666
<% if current_user.administrator? && @submission.sandbox %>
6767
<li>Sandbox used: <%= @submission.sandbox %></li>
68+
<li><%= link_to 'Difference with model solution', submission_difference_with_solution_path(@submission) %> (only for admins)</li>
6869
<% end %>
6970
</ul>
7071

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<h1>Submission difference</h1>
2+
3+
<div class="alert alert-warning">
4+
This is a naive and experimental feature that calculates the
5+
difference between this submission and the model solution.
6+
This may sometimes be helpful when trying to figure out what's wrong with
7+
a submission.
8+
</div>
9+
10+
<% @files.each do |file| %>
11+
<div class="card">
12+
<div class="card-body">
13+
<h2><%= file[:path] %></h2>
14+
<div class="code-pair" data-path="<%= file[:path] %>">
15+
<div class="submission-code"><%= file[:submission_contents] %></div>
16+
<div class="model-code"><%= file[:model_contents] %></div>
17+
</div>
18+
</div>
19+
</div>
20+
<br>
21+
<% end %>
22+
23+
<script src="https://cdnjs.cloudflare.com/ajax/libs/diff_match_patch/20121119/diff_match_patch.js" integrity="sha256-qsdlWiFdhEjZXZhx6NikCsPZqvONgasszEPBzSZ7j6M=" crossorigin="anonymous"></script>
24+
25+
<script>
26+
var dmp = new diff_match_patch();
27+
document.querySelectorAll('.code-pair').forEach(function (pairElement) {
28+
var path = pairElement.dataset.path;
29+
var submissionCode = pairElement.querySelector('.submission-code').innerHTML;
30+
var modelCode = pairElement.querySelector('.model-code').innerHTML;
31+
var diff = dmp.diff_main(modelCode, submissionCode);
32+
var outputHtml = dmp.diff_prettyHtml(diff).replace(/&para;/g, '');
33+
pairElement.innerHTML = outputHtml;
34+
});
35+
</script>
36+
37+
<style>
38+
ins, .code-pair span {
39+
font-family: monospace;
40+
white-space: pre;
41+
text-decoration: none;
42+
}
43+
</style>

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@
248248
resources :files, only: [:index]
249249
resources :reviews, only: [:index, :new, :create]
250250
resources :full_zip, only: [:index]
251+
get 'difference_with_solution', to: 'submissions#difference_with_solution'
251252
end
252253

253254
get 'paste/:paste_key', to: 'submissions#show', as: 'paste'

0 commit comments

Comments
 (0)