diff --git a/app/controllers/execution_environments_controller.rb b/app/controllers/execution_environments_controller.rb index 1e91c922..75bb604a 100644 --- a/app/controllers/execution_environments_controller.rb +++ b/app/controllers/execution_environments_controller.rb @@ -44,7 +44,7 @@ class ExecutionEnvironmentsController < ApplicationController FROM (SELECT user_id, exercise_id, - CASE WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' ELSE working_time END AS working_time_new + CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new FROM (SELECT user_id, exercise_id, diff --git a/app/controllers/external_users_controller.rb b/app/controllers/external_users_controller.rb index 52cdc2ef..65bcf4e6 100644 --- a/app/controllers/external_users_controller.rb +++ b/app/controllers/external_users_controller.rb @@ -32,7 +32,7 @@ class ExternalUsersController < ApplicationController score, id, CASE - WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' + WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new FROM diff --git a/app/helpers/statistics_helper.rb b/app/helpers/statistics_helper.rb index 049c5a42..0b4a95d7 100644 --- a/app/helpers/statistics_helper.rb +++ b/app/helpers/statistics_helper.rb @@ -2,7 +2,9 @@ module StatisticsHelper WORKING_TIME_DELTA_IN_SECONDS = 5.minutes - WORKING_TIME_DELTA_IN_SQL_INTERVAL = ActiveRecord::Base.sanitize_sql("'0:05:00'") # yes, a string with quotes + def self.working_time_larger_delta + @working_time_larger_delta ||= ActiveRecord::Base.sanitize_sql(['working_time >= ?', '0:05:00']) + end def statistics_data [ @@ -174,14 +176,12 @@ module StatisticsHelper end def ranged_rfc_data(interval = 'year', from = DateTime.new(0), to = DateTime.now) - interval = ActiveRecord::Base.sanitize_sql(interval) - [ { key: 'rfcs', name: t('activerecord.models.request_for_comment.other'), data: RequestForComment.in_range(from, to) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .select(RequestForComment.sanitize_sql(['date_trunc(?, created_at) AS "key", count(id) AS "value"', interval])) .group('key').order('key'), }, { @@ -189,7 +189,7 @@ module StatisticsHelper name: t('statistics.entries.request_for_comments.percent_solved'), data: RequestForComment.in_range(from, to) .where(solved: true) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .select(RequestForComment.sanitize_sql(['date_trunc(?, created_at) AS "key", count(id) AS "value"', interval])) .group('key').order('key'), }, { @@ -197,36 +197,34 @@ module StatisticsHelper name: t('statistics.entries.request_for_comments.percent_soft_solved'), data: RequestForComment.in_range(from, to).unsolved .where(full_score_reached: true) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .select(RequestForComment.sanitize_sql(['date_trunc(?, created_at) AS "key", count(id) AS "value"', interval])) .group('key').order('key'), }, { key: 'rfcs_unsolved', name: t('statistics.entries.request_for_comments.percent_unsolved'), data: RequestForComment.in_range(from, to).unsolved - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .select(RequestForComment.sanitize_sql(['date_trunc(?, created_at) AS "key", count(id) AS "value"', interval])) .group('key').order('key'), }, ] end def ranged_user_data(interval = 'year', from = DateTime.new(0), to = DateTime.now) - interval = ActiveRecord::Base.sanitize_sql(interval) - [ { key: 'active', name: t('statistics.entries.users.active'), data: ExternalUser.joins(:submissions) .where(submissions: {created_at: from..to}) - .select("date_trunc('#{interval}', submissions.created_at) AS \"key\", count(distinct external_users.id) AS \"value\"") + .select(ExternalUser.sanitize_sql(['date_trunc(?, submissions.created_at) AS "key", count(distinct external_users.id) AS "value"', interval])) .group('key').order('key'), }, { key: 'submissions', name: t('statistics.entries.exercises.submissions'), data: Submission.where(created_at: from..to) - .select("date_trunc('#{interval}', created_at) AS \"key\", count(id) AS \"value\"") + .select(Submission.sanitize_sql(['date_trunc(?, created_at) AS "key", count(id) AS "value"', interval])) .group('key').order('key'), axis: 'right', }, diff --git a/app/models/exercise.rb b/app/models/exercise.rb index 308dc7d7..bd27750c 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -94,7 +94,7 @@ class Exercise < ApplicationRecord (SELECT user_id, user_type, score, - CASE WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' ELSE working_time END AS working_time_new + CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new FROM (SELECT user_id, user_type, @@ -103,7 +103,7 @@ class Exercise < ApplicationRecord (created_at - lag(created_at) over (PARTITION BY user_id, exercise_id ORDER BY created_at)) AS working_time FROM submissions - WHERE exercise_id=#{self.class.sanitize_sql(id)}) AS foo) AS bar + WHERE #{self.class.sanitize_sql(['exercise_id = ?', id])}) AS foo) AS bar GROUP BY user_id, user_type " end @@ -118,7 +118,7 @@ class Exercise < ApplicationRecord (created_at - lag(created_at) over (PARTITION BY submissions.user_type, submissions.user_id, exercise_id ORDER BY created_at)) AS working_time FROM submissions - WHERE exercise_id = #{self.class.sanitize_sql(exercise_id)} AND study_group_id = #{self.class.sanitize_sql(study_group_id)} #{self.class.sanitize_sql(additional_filter)}), + WHERE #{self.class.sanitize_sql(['exercise_id = ? and study_group_id = ?', exercise_id, study_group_id])} #{self.class.sanitize_sql(additional_filter)}), working_time_with_deltas_ignored AS ( SELECT user_id, user_type, @@ -126,7 +126,7 @@ class Exercise < ApplicationRecord sum(CASE WHEN score IS NOT NULL THEN 1 ELSE 0 END) over (ORDER BY user_type, user_id, created_at ASC) AS change_in_score, created_at, - CASE WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' ELSE working_time END AS working_time_filtered + CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_filtered FROM working_time_between_submissions ), working_times_with_score_expanded AS ( @@ -263,7 +263,7 @@ class Exercise < ApplicationRecord Max(score) AS max_score, (created_at - Lag(created_at) OVER (partition BY user_id, exercise_id ORDER BY created_at)) AS working_time FROM submissions - WHERE exercise_id = #{self.class.sanitize_sql(id)} + WHERE #{self.class.sanitize_sql(['exercise_id = ?', id])} AND user_type = 'ExternalUser' GROUP BY user_id, id, @@ -273,7 +273,7 @@ class Exercise < ApplicationRecord Sum(weight) AS max_points FROM files WHERE context_type = 'Exercise' - AND context_id = #{self.class.sanitize_sql(id)} + AND #{self.class.sanitize_sql(['context_id = ?', id])} AND role IN ('teacher_defined_test', 'teacher_defined_linter') GROUP BY context_id), -- filter for rows containing max points @@ -342,7 +342,7 @@ class Exercise < ApplicationRecord exercise_id, max_score, CASE - WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' + WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new FROM all_working_times_until_max ), result AS @@ -445,7 +445,7 @@ class Exercise < ApplicationRecord FILTERED_TIMES_UNTIL_MAX AS ( - SELECT user_id,exercise_id, max_score, CASE WHEN working_time >= #{StatisticsHelper::WORKING_TIME_DELTA_IN_SQL_INTERVAL} THEN '0' ELSE working_time END AS working_time_new + SELECT user_id,exercise_id, max_score, CASE WHEN #{StatisticsHelper.working_time_larger_delta} THEN '0' ELSE working_time END AS working_time_new FROM ALL_WORKING_TIMES_UNTIL_MAX ) SELECT e.external_id AS external_user_id, f.user_id, exercise_id, MAX(max_score) AS max_score, sum(working_time_new) AS working_time diff --git a/lib/tasks/detect_exercise_anomalies.rake b/lib/tasks/detect_exercise_anomalies.rake index 8c180193..a3de8735 100644 --- a/lib/tasks/detect_exercise_anomalies.rake +++ b/lib/tasks/detect_exercise_anomalies.rake @@ -63,7 +63,7 @@ namespace :detect_exercise_anomalies do from exercises e join submissions s on s.exercise_id = e.id group by e.id - having count(s.user_id) > #{ExerciseCollection.sanitize_sql(number_of_solutions)} + having #{ExerciseCollection.sanitize_sql(['count(s.user_id) > ?', number_of_solutions])} ) as exercises_with_submissions on exercises_with_submissions.id = eci.exercise_id") .group('exercise_collections.id') .having('count(exercises_with_submissions.id) > ?', number_of_exercises)