Files
codeocean/app/models/request_for_comment.rb
Sebastian Serth 7cc4fb00c6 RfCs: Allow filtering for any states
We want to differentiate between those RfCs explicitly marked as solved, those potentially solved since the author reached the maximum score, and those being unsolved where the author has not yet reached the full score yet.
2024-04-24 12:18:47 +02:00

124 lines
3.9 KiB
Ruby

# frozen_string_literal: true
class RequestForComment < ApplicationRecord
include Creation
include ActionCableHelper
# SOLVED: The author explicitly marked the RfC as solved.
# SOFT_SOLVED: The author did not mark the RfC as solved but reached the maximum score in the corresponding exercise at any time.
# ONGOING: The author did not mark the RfC as solved and did not reach the maximum score in the corresponding exercise yet.
# ALL: Any RfC, regardless of the author marking it as solved or reaching the maximum score in the corresponding exercise.
STATE = [SOLVED = :solved, SOFT_SOLVED = :soft_solved, ONGOING = :unsolved, ALL = :all].freeze
belongs_to :submission
belongs_to :exercise
belongs_to :file, class_name: 'CodeOcean::File'
has_many :comments, through: :submission
has_many :subscriptions, dependent: :destroy
scope :unsolved, -> { where(solved: [false, nil]) }
scope :in_range, ->(from, to) { from == DateTime.new(0) && to > 5.seconds.ago ? all : where(created_at: from..to) }
scope :with_comments, -> { select {|rfc| rfc.comments.any? } }
# after_save :trigger_rfc_action_cable
def commenters
comments.map(&:user).uniq
end
def comments?
comments.any?
end
def to_s
"RFC-#{id}"
end
def current_state
state(solved, full_score_reached)
end
def old_state
state(solved_before_last_save, full_score_reached_before_last_save)
end
def self.parent_resource
Exercise
end
private
def state(solved, full_score_reached)
if solved
SOLVED
elsif full_score_reached
SOFT_SOLVED
else
ONGOING
end
end
class << self
def state(filter = RequestForComment::ALL)
# This method is used as a scope filter for Ransack
case filter.to_sym
when RequestForComment::SOLVED
where(solved: true)
when RequestForComment::SOFT_SOLVED
unsolved.where(full_score_reached: true)
when RequestForComment::ONGOING
unsolved.where(full_score_reached: false)
else # 'all'
all
end
end
def with_last_activity
joins('join "submissions" s on s.id = request_for_comments.submission_id ' \
'left outer join "files" f on f.context_id = s.id ' \
'left outer join "comments" c on c.file_id = f.id')
.group('request_for_comments.id')
.select('request_for_comments.*, max(c.updated_at) as last_comment')
end
def last_per_user(count = 5)
from(row_number_user_sql, :request_for_comments)
.where('row_number <= ?', count)
.group('request_for_comments.id, request_for_comments.user_id, request_for_comments.user_type, ' \
'request_for_comments.exercise_id, request_for_comments.file_id, request_for_comments.question, ' \
'request_for_comments.created_at, request_for_comments.updated_at, request_for_comments.solved, ' \
'request_for_comments.full_score_reached, request_for_comments.submission_id, request_for_comments.row_number')
# ugly, but necessary
end
def ransackable_associations(_auth_object = nil)
%w[exercise submission]
end
def ransackable_scopes(_auth_object = nil)
%w[state]
end
private
def row_number_user_sql
select('
request_for_comments.id,
request_for_comments.user_id,
request_for_comments.user_type,
request_for_comments.exercise_id,
request_for_comments.file_id,
request_for_comments.question,
request_for_comments.created_at,
request_for_comments.updated_at,
request_for_comments.solved,
request_for_comments.full_score_reached,
request_for_comments.submission_id,
row_number() OVER (PARTITION BY request_for_comments.user_id, request_for_comments.user_type ORDER BY request_for_comments.created_at DESC) as row_number
')
end
end
end