merged master into disable_rfcs

This commit is contained in:
Ralf Teusner
2018-05-16 17:44:28 +02:00
82 changed files with 2007 additions and 376 deletions

View File

@@ -0,0 +1,5 @@
class AnomalyNotification < ActiveRecord::Base
belongs_to :user, polymorphic: true
belongs_to :exercise
belongs_to :exercise_collection
end

View File

@@ -36,6 +36,7 @@ class Exercise < ActiveRecord::Base
validates :token, presence: true, uniqueness: true
@working_time_statistics = nil
attr_reader :working_time_statistics
MAX_EXERCISE_FEEDBACKS = 20
@@ -65,21 +66,27 @@ class Exercise < ActiveRecord::Base
end
def user_working_time_query
"""
"
SELECT user_id,
sum(working_time_new) AS working_time
user_type,
SUM(working_time_new) AS working_time,
MAX(score) AS score
FROM
(SELECT user_id,
user_type,
score,
CASE WHEN working_time >= '0:05:00' THEN '0' ELSE working_time END AS working_time_new
FROM
(SELECT user_id,
user_type,
score,
id,
(created_at - lag(created_at) over (PARTITION BY user_id, exercise_id
ORDER BY created_at)) AS working_time
FROM submissions
WHERE exercise_id=#{id}) AS foo) AS bar
GROUP BY user_id
"""
GROUP BY user_id, user_type
"
end
def get_quantiles(quantiles)
@@ -202,7 +209,7 @@ class Exercise < ActiveRecord::Base
def retrieve_working_time_statistics
@working_time_statistics = {}
self.class.connection.execute(user_working_time_query).each do |tuple|
@working_time_statistics[tuple["user_id"].to_i] = tuple
@working_time_statistics[tuple['user_id'].to_i] = tuple
end
end
@@ -345,7 +352,11 @@ class Exercise < ActiveRecord::Base
end
def has_user_solved(user)
return maximum_score(user).to_i == maximum_score.to_i
maximum_score(user).to_i == maximum_score.to_i
end
def finishers
ExternalUser.joins(:submissions).where(submissions: {exercise_id: id, score: maximum_score, cause: %w(submit assess)}).distinct
end
def set_default_values
@@ -368,4 +379,15 @@ class Exercise < ActiveRecord::Base
user_exercise_feedbacks.size <= MAX_EXERCISE_FEEDBACKS
end
def last_submission_per_user
Submission.joins("JOIN (
SELECT
user_id,
user_type,
first_value(id) OVER (PARTITION BY user_id ORDER BY created_at DESC) AS fv
FROM submissions
WHERE exercise_id = #{id}
) AS t ON t.fv = submissions.id").distinct
end
end

View File

@@ -1,6 +1,25 @@
class ExerciseCollection < ActiveRecord::Base
include TimeHelper
has_and_belongs_to_many :exercises
belongs_to :user, polymorphic: true
def exercise_working_times
working_times = {}
exercises.each do |exercise|
working_times[exercise.id] = time_to_f exercise.average_working_time
end
working_times
end
def average_working_time
if exercises.empty?
0
else
values = exercise_working_times.values.reject { |v| v.nil?}
values.reduce(:+) / exercises.size
end
end
def to_s
"#{I18n.t('activerecord.models.exercise_collection.one')}: #{name} (#{id})"

View File

@@ -8,6 +8,7 @@ class RequestForComment < ActiveRecord::Base
has_many :subscriptions
scope :unsolved, -> { where(solved: [false, nil]) }
scope :in_range, -> (from, to) { where(created_at: from..to) }
def self.last_per_user(n = 5)
from("(#{row_number_user_sql}) as request_for_comments")

View File

@@ -3,11 +3,21 @@ class StructuredError < ActiveRecord::Base
belongs_to :submission
belongs_to :file, class_name: 'CodeOcean::File'
has_many :structured_error_attributes
def self.create_from_template(template, message_buffer, submission)
instance = self.create(error_template: template, submission: submission)
template.error_template_attributes.each do |attribute|
template.error_template_attributes.each do | attribute |
StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer)
end
instance
end
def hint
content = error_template.hint
structured_error_attributes.each do | attribute |
content.sub! "{{#{attribute.error_template_attribute.key}}}", attribute.value if attribute.match
end
content
end
end