merge master
This commit is contained in:
3
app/assets/config/manifest.js
Normal file
3
app/assets/config/manifest.js
Normal file
@@ -0,0 +1,3 @@
|
||||
//= link_tree ../images
|
||||
//= link_directory ../javascripts .js
|
||||
//= link_directory ../stylesheets .css
|
@@ -252,7 +252,11 @@ configureEditors: function () {
|
||||
this.editors.push(editor);
|
||||
this.editor_for_file.set($(element).parent().data('filename'), editor);
|
||||
var session = editor.getSession();
|
||||
session.setMode($(element).data('mode'));
|
||||
var mode = $(element).data('mode')
|
||||
session.setMode(mode);
|
||||
if (mode === 'ace/mode/python') {
|
||||
editor.setTheme('ace/theme/tomorrow')
|
||||
}
|
||||
session.setTabSize($(element).data('indent-size'));
|
||||
session.setUseSoftTabs(true);
|
||||
session.setUseWrapMode(true);
|
||||
|
@@ -7,7 +7,7 @@ class ExercisesController < ApplicationController
|
||||
|
||||
before_action :handle_file_uploads, only: [:create, :update]
|
||||
before_action :set_execution_environments, only: [:create, :edit, :new, :update]
|
||||
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :study_group_dashboard, :export_external_check, :export_external_confirm]
|
||||
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :requests_for_comments, :study_group_dashboard, :export_external_check, :export_external_confirm]
|
||||
before_action :set_external_user_and_authorize, only: [:statistics]
|
||||
before_action :set_file_types, only: [:create, :edit, :new, :update]
|
||||
before_action :set_course_token, only: [:implement]
|
||||
@@ -104,6 +104,21 @@ class ExercisesController < ApplicationController
|
||||
def feedback
|
||||
authorize!
|
||||
@feedbacks = @exercise.user_exercise_feedbacks.paginate(page: params[:page])
|
||||
@submissions = @feedbacks.map do |feedback|
|
||||
feedback.exercise.final_submission(feedback.user)
|
||||
end
|
||||
end
|
||||
|
||||
def requests_for_comments
|
||||
authorize!
|
||||
@search = RequestForComment
|
||||
.with_last_activity
|
||||
.where(exercise: @exercise)
|
||||
.ransack(params[:q])
|
||||
@request_for_comments = @search.result
|
||||
.order('last_comment DESC')
|
||||
.paginate(page: params[:page])
|
||||
render 'request_for_comments/index'
|
||||
end
|
||||
|
||||
def export_external_check
|
||||
@@ -377,6 +392,7 @@ class ExercisesController < ApplicationController
|
||||
|
||||
def statistics
|
||||
if(@external_user)
|
||||
authorize(@external_user, :statistics?)
|
||||
@submissions = Submission.where("user_id = ? AND exercise_id = ?", @external_user.id, @exercise.id).order("created_at")
|
||||
interventions = UserExerciseIntervention.where("user_id = ? AND exercise_id = ?", @external_user.id, @exercise.id)
|
||||
@all_events = (@submissions + interventions).sort_by { |a| a.created_at }
|
||||
|
@@ -20,8 +20,8 @@ class SessionsController < ApplicationController
|
||||
def create_through_lti
|
||||
store_lti_session_data(consumer: @consumer, parameters: params)
|
||||
store_nonce(params[:oauth_nonce])
|
||||
if params[:redirect_target]
|
||||
redirect_to(params[:redirect_target])
|
||||
if params[:custom_redirect_target]
|
||||
redirect_to(params[:custom_redirect_target])
|
||||
else
|
||||
redirect_to(implement_exercise_path(@exercise),
|
||||
notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id , @consumer.id) ? 'with' : 'without'}_outcome",
|
||||
|
@@ -494,12 +494,17 @@ class Exercise < ApplicationRecord
|
||||
|
||||
def maximum_score(user = nil)
|
||||
if user
|
||||
# FIXME: where(user: user) will not work here!
|
||||
submissions.where(user: user).where("cause IN ('submit','assess')").where("score IS NOT NULL").order("score DESC").first.score || 0 rescue 0
|
||||
else
|
||||
files.teacher_defined_tests.sum(:weight)
|
||||
end
|
||||
end
|
||||
|
||||
def final_submission(user)
|
||||
submissions.final.where(user_id: user.id, user_type: user.class.name).order(created_at: :desc).first
|
||||
end
|
||||
|
||||
def has_user_solved(user)
|
||||
maximum_score(user).to_i == maximum_score.to_i
|
||||
end
|
||||
|
@@ -3,11 +3,11 @@ class ExercisePolicy < AdminOrAuthorPolicy
|
||||
admin?
|
||||
end
|
||||
|
||||
[:show?, :study_group_dashboard?].each do |action|
|
||||
[:show?, :study_group_dashboard?, :feedback?, :requests_for_comments?, :statistics?].each do |action|
|
||||
define_method(action) { admin? || teacher? }
|
||||
end
|
||||
|
||||
[:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?, :export_external_check?, :export_external_confirm?].each do |action|
|
||||
[:clone?, :destroy?, :edit?, :update?, :export_external_check?, :export_external_confirm?].each do |action|
|
||||
define_method(action) { admin? || author? }
|
||||
end
|
||||
|
||||
|
@@ -4,12 +4,17 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
|
||||
.header = t('activerecord.attributes.exercise.description')
|
||||
.value = render_markdown(@exercise.description)
|
||||
|
||||
.header = t('activerecord.models.user_exercise_feedback.other')
|
||||
span.header.col-sm-3.pl-0 = "#{t('activerecord.attributes.exercise.maximum_score')}"
|
||||
span.col-sm-9 = @exercise.maximum_score
|
||||
|
||||
.header.mt-3 = t('activerecord.models.user_exercise_feedback.other')
|
||||
- if @feedbacks.nil? or @feedbacks.size == 0
|
||||
.no-feedback = t('user_exercise_feedback.no_feedback')
|
||||
|
||||
ul.list-unstyled
|
||||
- @feedbacks.each do |feedback|
|
||||
- comment_presets = UserExerciseFeedbacksController.new.comment_presets
|
||||
- time_presets = UserExerciseFeedbacksController.new.time_presets
|
||||
- @feedbacks.each_with_index do |feedback, index|
|
||||
li.card.mt-2
|
||||
.card-header role="tab" id="heading"
|
||||
div.clearfix.feedback-header
|
||||
@@ -20,8 +25,11 @@ h1 = link_to_if(policy(@exercise).show?, @exercise, exercise_path(@exercise))
|
||||
.card-collapse role="tabpanel"
|
||||
.card-body.feedback
|
||||
.text = feedback.feedback_text
|
||||
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{feedback.difficulty}" if feedback.difficulty
|
||||
.worktime = "#{t('user_exercise_feedback.working_time')} #{feedback.user_estimated_worktime}" if feedback.user_estimated_worktime
|
||||
.difficulty = "#{t('user_exercise_feedback.difficulty')} #{comment_presets[feedback.difficulty].join(' - ')}" if feedback.difficulty
|
||||
.worktime = "#{t('user_exercise_feedback.working_time')} #{time_presets[feedback.user_estimated_worktime].join(' - ')}" if feedback.user_estimated_worktime
|
||||
.card-footer
|
||||
span.points = "#{t('exercises.statistics.score')}: #{@submissions[index].score}"
|
||||
span.working_time.pull-right = "#{t('exercises.statistics.worktime')}: #{@exercise.average_working_time_for(feedback.user.id) or 0}"
|
||||
|
||||
= render('shared/pagination', collection: @feedbacks)
|
||||
|
||||
|
@@ -44,6 +44,7 @@ h1 = Exercise.model_name.human(count: 2)
|
||||
ul.dropdown-menu.float-right role="menu"
|
||||
li = link_to(t('shared.show'), exercise, 'data-turbolinks' => "false", class: 'dropdown-item') if policy(exercise).show?
|
||||
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).feedback?
|
||||
li = link_to(t('activerecord.models.request_for_comment.other'), requests_for_comments_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).requests_for_comments?
|
||||
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(exercise).destroy?
|
||||
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(exercise).clone?
|
||||
li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id' => exercise.id}) if policy(exercise).export_external_confirm?
|
||||
|
@@ -38,18 +38,19 @@ h1 = @exercise
|
||||
hr
|
||||
div#chart_2
|
||||
hr
|
||||
.table-responsive
|
||||
table.table.table-striped.sortable
|
||||
thead
|
||||
tr
|
||||
- ['.user', '.score', '.runs', '.worktime'].each do |title|
|
||||
th.header = t(title)
|
||||
tbody
|
||||
- @exercise.send(symbol).distinct().each do |user|
|
||||
- if user_statistics[user.id] then us = user_statistics[user.id] else us = {"maximum_score" => nil, "runs" => nil}
|
||||
- label = "#{user.displayname}"
|
||||
- if current_user.admin?
|
||||
.table-responsive
|
||||
table.table.table-striped.sortable
|
||||
thead
|
||||
tr
|
||||
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
|
||||
td = us['maximum_score'] or 0
|
||||
td = us['runs']
|
||||
td = @exercise.average_working_time_for(user.id) or 0
|
||||
- ['.user', '.score', '.runs', '.worktime'].each do |title|
|
||||
th.header = t(title)
|
||||
tbody
|
||||
- @exercise.send(symbol).distinct().each do |user|
|
||||
- if user_statistics[user.id] then us = user_statistics[user.id] else us = {"maximum_score" => nil, "runs" => nil}
|
||||
- label = "#{user.displayname}"
|
||||
tr
|
||||
td = link_to_if symbol==:external_users && policy(user).statistics?, label, {controller: "exercises", action: "statistics", external_user_id: user.id, id: @exercise.id}
|
||||
td = us['maximum_score'] or 0
|
||||
td = us['runs']
|
||||
td = @exercise.average_working_time_for(user.id) or 0
|
||||
|
Reference in New Issue
Block a user