Extract Contributor concern as abstract class

During documentation of the pair programming feature, we noticed that the Contributor should be an abstract class, which is parent for the User and the ProgrammingGroup. With this commit, we perform these changes.
This commit is contained in:
Sebastian Serth
2024-02-13 14:31:45 +01:00
committed by Sebastian Serth
parent 37e5dfaba1
commit dab8f777b3
6 changed files with 53 additions and 76 deletions

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
module Contributor
extend ActiveSupport::Concern
included do
has_many :submissions, as: :contributor
end
end

View File

@ -2,7 +2,6 @@
module ContributorCreation module ContributorCreation
extend ActiveSupport::Concern extend ActiveSupport::Concern
include Contributor
ALLOWED_CONTRIBUTOR_TYPES = [InternalUser, ExternalUser, ProgrammingGroup].map(&:to_s).freeze ALLOWED_CONTRIBUTOR_TYPES = [InternalUser, ExternalUser, ProgrammingGroup].map(&:to_s).freeze

48
app/models/contributor.rb Normal file
View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
class Contributor < ApplicationRecord
self.abstract_class = true
has_many :anomaly_notifications, as: :contributor, dependent: :destroy
has_many :user_exercise_interventions, as: :contributor
has_many :runners, as: :contributor, dependent: :destroy
has_many :submissions, as: :contributor
def learner?
raise NotImplementedError
end
def teacher?
raise NotImplementedError
end
def admin?
raise NotImplementedError
end
def internal_user?
is_a?(InternalUser)
end
def external_user?
is_a?(ExternalUser)
end
def programming_group?
is_a?(ProgrammingGroup)
end
def to_s
displayname
end
def to_page_context
{
id:,
type: self.class.name,
consumer: try(:consumer)&.name, # Only a user is associated with a consumer.
displayname:,
}
end
end

View File

@ -1,19 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class ProgrammingGroup < ApplicationRecord class ProgrammingGroup < Contributor
include Contributor
has_many :anomaly_notifications, as: :contributor, dependent: :destroy
has_many :programming_group_memberships, dependent: :destroy has_many :programming_group_memberships, dependent: :destroy
has_many :external_users, through: :programming_group_memberships, source_type: 'ExternalUser', source: :user has_many :external_users, through: :programming_group_memberships, source_type: 'ExternalUser', source: :user
has_many :internal_users, through: :programming_group_memberships, source_type: 'InternalUser', source: :user has_many :internal_users, through: :programming_group_memberships, source_type: 'InternalUser', source: :user
has_many :testruns, through: :submissions has_many :testruns, through: :submissions # Only a single user starts testruns, but the group has access to them through their submissions.
has_many :runners, as: :contributor, dependent: :destroy has_many :events, dependent: :destroy # Only a single user creates events, but the group might be attributed to them optionally.
has_many :events, dependent: :destroy
has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor', dependent: :destroy has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor', dependent: :destroy
has_many :pair_programming_exercise_feedbacks, dependent: :destroy has_many :pair_programming_exercise_feedbacks, dependent: :destroy
has_many :pair_programming_waiting_users, dependent: :destroy has_many :pair_programming_waiting_users, dependent: :destroy
has_many :user_exercise_interventions, as: :contributor
belongs_to :exercise belongs_to :exercise
validate :min_group_size validate :min_group_size
@ -21,14 +16,6 @@ class ProgrammingGroup < ApplicationRecord
validate :no_erroneous_users validate :no_erroneous_users
accepts_nested_attributes_for :programming_group_memberships accepts_nested_attributes_for :programming_group_memberships
def external_user?
false
end
def internal_user?
false
end
def learner? def learner?
true true
end end
@ -45,10 +32,6 @@ class ProgrammingGroup < ApplicationRecord
Exercise Exercise
end end
def programming_group?
true
end
def add(user) def add(user)
# Accessing the `users` method here will preload all users, which is otherwise done during validation. # Accessing the `users` method here will preload all users, which is otherwise done during validation.
internal_users << user if user.internal_user? && users.exclude?(user) internal_users << user if user.internal_user? && users.exclude?(user)
@ -56,23 +39,10 @@ class ProgrammingGroup < ApplicationRecord
user user
end end
def to_s
displayname
end
def displayname def displayname
"Programming Group #{id}" "Programming Group #{id}"
end end
def to_page_context
{
id:,
type: self.class.name,
consumer: nil, # A programming group is not associated with a consumer.
displayname:,
}
end
def programming_partner_ids def programming_partner_ids
users.map(&:id_with_type) users.map(&:id_with_type)
end end

View File

@ -1,12 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
class User < ApplicationRecord class User < Contributor
self.abstract_class = true self.abstract_class = true
attr_reader :current_study_group_id attr_reader :current_study_group_id
belongs_to :consumer belongs_to :consumer
has_many :anomaly_notifications, as: :contributor, dependent: :destroy
has_many :authentication_token, dependent: :destroy has_many :authentication_token, dependent: :destroy
has_many :comments, as: :user has_many :comments, as: :user
has_many :study_group_memberships, as: :user has_many :study_group_memberships, as: :user
@ -15,15 +14,12 @@ class User < ApplicationRecord
has_many :programming_groups, through: :programming_group_memberships, as: :user has_many :programming_groups, through: :programming_group_memberships, as: :user
has_many :exercises, as: :user has_many :exercises, as: :user
has_many :file_types, as: :user has_many :file_types, as: :user
has_many :submissions, as: :contributor
has_many :participations, through: :submissions, source: :exercise, as: :user has_many :participations, through: :submissions, source: :exercise, as: :user
has_many :user_proxy_exercise_exercises, as: :user has_many :user_proxy_exercise_exercises, as: :user
has_many :user_exercise_interventions, as: :contributor
has_many :testruns, as: :user has_many :testruns, as: :user
has_many :interventions, through: :user_exercise_interventions has_many :interventions, through: :user_exercise_interventions
has_many :remote_evaluation_mappings, as: :user has_many :remote_evaluation_mappings, as: :user
has_many :request_for_comments, as: :user has_many :request_for_comments, as: :user
has_many :runners, as: :contributor
has_many :events has_many :events
has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor' has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor'
has_many :pair_programming_exercise_feedbacks has_many :pair_programming_exercise_feedbacks
@ -31,8 +27,6 @@ class User < ApplicationRecord
has_one :codeharbor_link, dependent: :destroy has_one :codeharbor_link, dependent: :destroy
accepts_nested_attributes_for :user_proxy_exercise_exercises accepts_nested_attributes_for :user_proxy_exercise_exercises
scope :with_submissions, -> { where('id IN (SELECT user_id FROM submissions)') }
scope :in_study_group_of, lambda {|user| scope :in_study_group_of, lambda {|user|
unless user.admin? unless user.admin?
joins(:study_group_memberships) joins(:study_group_memberships)
@ -46,18 +40,6 @@ class User < ApplicationRecord
validates :platform_admin, inclusion: [true, false] validates :platform_admin, inclusion: [true, false]
def internal_user?
is_a?(InternalUser)
end
def external_user?
is_a?(ExternalUser)
end
def programming_group?
false
end
def learner? def learner?
return true if current_study_group_id.nil? return true if current_study_group_id.nil?
@ -86,19 +68,6 @@ class User < ApplicationRecord
study_group_memberships.where(study_group: current_study_group_id).limit(1) study_group_memberships.where(study_group: current_study_group_id).limit(1)
end end
def to_s
displayname
end
def to_page_context
{
id:,
type: self.class.name,
consumer: consumer.name,
displayname:,
}
end
def self.find_by_id_with_type(id_with_type) def self.find_by_id_with_type(id_with_type)
if id_with_type[0].casecmp('e').zero? if id_with_type[0].casecmp('e').zero?
ExternalUser.find(id_with_type[1..]) ExternalUser.find(id_with_type[1..])

View File

@ -28,7 +28,7 @@ end
# delete all present records # delete all present records
Rails.application.eager_load! Rails.application.eager_load!
(ApplicationRecord.descendants - [ActiveRecord::SchemaMigration, User]).each(&:delete_all) (ApplicationRecord.descendants - [ActiveRecord::SchemaMigration, Contributor, User]).each(&:delete_all)
# delete file uploads # delete file uploads
FileUtils.rm_rf(Rails.public_path.join('uploads')) FileUtils.rm_rf(Rails.public_path.join('uploads'))