Migrate database and models for study-group-based authorization
This commit is contained in:

committed by
Sebastian Serth

parent
ec4c6207f0
commit
04ed45ea73
@ -4,6 +4,7 @@ require 'securerandom'
|
|||||||
|
|
||||||
class AuthenticationToken < ApplicationRecord
|
class AuthenticationToken < ApplicationRecord
|
||||||
include Creation
|
include Creation
|
||||||
|
belongs_to :study_group, optional: true
|
||||||
|
|
||||||
def self.generate!(user)
|
def self.generate!(user)
|
||||||
create!(
|
create!(
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
class Consumer < ApplicationRecord
|
class Consumer < ApplicationRecord
|
||||||
has_many :users
|
has_many :users
|
||||||
|
has_many :study_groups, dependent: :destroy
|
||||||
|
|
||||||
scope :with_internal_users, -> { where('id IN (SELECT DISTINCT consumer_id FROM internal_users)') }
|
scope :with_internal_users, -> { where('id IN (SELECT DISTINCT consumer_id FROM internal_users)') }
|
||||||
scope :with_external_users, -> { where('id IN (SELECT DISTINCT consumer_id FROM external_users)') }
|
scope :with_external_users, -> { where('id IN (SELECT DISTINCT consumer_id FROM external_users)') }
|
||||||
|
@ -6,6 +6,8 @@ class StudyGroup < ApplicationRecord
|
|||||||
has_many :internal_users, through: :study_group_memberships, source_type: 'InternalUser', source: :user
|
has_many :internal_users, through: :study_group_memberships, source_type: 'InternalUser', source: :user
|
||||||
has_many :submissions, dependent: :nullify
|
has_many :submissions, dependent: :nullify
|
||||||
has_many :remote_evaluation_mappings, dependent: :nullify
|
has_many :remote_evaluation_mappings, dependent: :nullify
|
||||||
|
has_many :subscriptions, dependent: :nullify
|
||||||
|
has_many :authentication_tokens, dependent: :nullify
|
||||||
belongs_to :consumer
|
belongs_to :consumer
|
||||||
|
|
||||||
def users
|
def users
|
||||||
|
@ -4,5 +4,11 @@ class StudyGroupMembership < ApplicationRecord
|
|||||||
belongs_to :user, polymorphic: true
|
belongs_to :user, polymorphic: true
|
||||||
belongs_to :study_group
|
belongs_to :study_group
|
||||||
|
|
||||||
|
enum role: {
|
||||||
|
learner: 0,
|
||||||
|
teacher: 1,
|
||||||
|
}, _default: :learner, _prefix: true
|
||||||
|
|
||||||
|
validates :role, presence: true
|
||||||
validates :user_id, uniqueness: {scope: %i[user_type study_group_id]}
|
validates :user_id, uniqueness: {scope: %i[user_type study_group_id]}
|
||||||
end
|
end
|
||||||
|
@ -3,4 +3,5 @@
|
|||||||
class Subscription < ApplicationRecord
|
class Subscription < ApplicationRecord
|
||||||
belongs_to :user, polymorphic: true
|
belongs_to :user, polymorphic: true
|
||||||
belongs_to :request_for_comment
|
belongs_to :request_for_comment
|
||||||
|
belongs_to :study_group, optional: true
|
||||||
end
|
end
|
||||||
|
11
db/migrate/20220906142041_add_study_group_authorization.rb
Normal file
11
db/migrate/20220906142041_add_study_group_authorization.rb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddStudyGroupAuthorization < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :external_users, :platform_admin, :boolean, default: false, nil: false
|
||||||
|
add_column :internal_users, :platform_admin, :boolean, default: false, nil: false
|
||||||
|
add_column :study_group_memberships, :role, :integer, limit: 1, null: false, default: 0, comment: 'Used as enum in Rails'
|
||||||
|
add_reference :subscriptions, :study_group, index: true, null: true, foreign_key: true
|
||||||
|
add_reference :authentication_tokens, :study_group, index: true, null: true, foreign_key: true
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,39 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MigratePermissionsToStudyGroup < ActiveRecord::Migration[6.1]
|
||||||
|
# rubocop:disable Rails/SkipsModelValidations
|
||||||
|
def up
|
||||||
|
create_default_groups
|
||||||
|
migrate_internal_users
|
||||||
|
migrate_external_users
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_default_groups
|
||||||
|
Consumer.find_each do |consumer|
|
||||||
|
StudyGroup.find_or_create_by!(consumer: consumer, external_id: nil) do |new_group|
|
||||||
|
new_group.name = "Default Study Group for #{consumer.name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def migrate_internal_users
|
||||||
|
# Internal users don't necessarily have a study group yet, which is needed for the teacher role
|
||||||
|
InternalUser.find_each do |user|
|
||||||
|
user.update_columns(platform_admin: true) if user.role == 'admin'
|
||||||
|
|
||||||
|
study_group = StudyGroup.find_by!(consumer: user.consumer, external_id: nil)
|
||||||
|
|
||||||
|
# All platform admins will "just" be a teacher in the study group
|
||||||
|
new_role = %w[admin teacher].include?(user.role) ? :teacher : :learner
|
||||||
|
membership = StudyGroupMembership.find_or_create_by!(study_group: study_group, user: user)
|
||||||
|
membership.update_columns(role: new_role)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def migrate_external_users
|
||||||
|
# All external users are (or will be) in a study group once launched through LTI
|
||||||
|
# and therefore don't need a new StudyGroupMembership
|
||||||
|
ExternalUser.where(role: 'admin').update(platform_admin: true)
|
||||||
|
end
|
||||||
|
# rubocop:enable Rails/SkipsModelValidations
|
||||||
|
end
|
8
db/migrate/20220906142603_remove_role_from_users.rb
Normal file
8
db/migrate/20220906142603_remove_role_from_users.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveRoleFromUsers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
remove_column :external_users, :role
|
||||||
|
remove_column :internal_users, :role
|
||||||
|
end
|
||||||
|
end
|
13
db/schema.rb
13
db/schema.rb
@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
ActiveRecord::Schema.define(version: 2022_09_06_142603) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pg_trgm"
|
enable_extension "pg_trgm"
|
||||||
@ -37,7 +37,9 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.datetime "expire_at", null: false
|
t.datetime "expire_at", null: false
|
||||||
t.datetime "created_at", precision: 6, null: false
|
t.datetime "created_at", precision: 6, null: false
|
||||||
t.datetime "updated_at", precision: 6, null: false
|
t.datetime "updated_at", precision: 6, null: false
|
||||||
|
t.bigint "study_group_id"
|
||||||
t.index ["shared_secret"], name: "index_authentication_tokens_on_shared_secret", unique: true
|
t.index ["shared_secret"], name: "index_authentication_tokens_on_shared_secret", unique: true
|
||||||
|
t.index ["study_group_id"], name: "index_authentication_tokens_on_study_group_id"
|
||||||
t.index ["user_type", "user_id"], name: "index_authentication_tokens_on_user"
|
t.index ["user_type", "user_id"], name: "index_authentication_tokens_on_user"
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -238,7 +240,7 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.string "name"
|
t.string "name"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "role", default: "learner", null: false
|
t.boolean "platform_admin", default: false
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "file_templates", id: :serial, force: :cascade do |t|
|
create_table "file_templates", id: :serial, force: :cascade do |t|
|
||||||
@ -288,7 +290,6 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.integer "consumer_id"
|
t.integer "consumer_id"
|
||||||
t.string "email"
|
t.string "email"
|
||||||
t.string "name"
|
t.string "name"
|
||||||
t.string "role"
|
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "crypted_password"
|
t.string "crypted_password"
|
||||||
@ -304,6 +305,7 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.string "activation_state"
|
t.string "activation_state"
|
||||||
t.string "activation_token"
|
t.string "activation_token"
|
||||||
t.datetime "activation_token_expires_at"
|
t.datetime "activation_token_expires_at"
|
||||||
|
t.boolean "platform_admin", default: false
|
||||||
t.index ["activation_token"], name: "index_internal_users_on_activation_token"
|
t.index ["activation_token"], name: "index_internal_users_on_activation_token"
|
||||||
t.index ["email"], name: "index_internal_users_on_email", unique: true
|
t.index ["email"], name: "index_internal_users_on_email", unique: true
|
||||||
t.index ["remember_me_token"], name: "index_internal_users_on_remember_me_token"
|
t.index ["remember_me_token"], name: "index_internal_users_on_remember_me_token"
|
||||||
@ -429,6 +431,7 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.bigint "study_group_id"
|
t.bigint "study_group_id"
|
||||||
t.string "user_type"
|
t.string "user_type"
|
||||||
t.bigint "user_id"
|
t.bigint "user_id"
|
||||||
|
t.integer "role", limit: 2, default: 0, null: false, comment: "Used as enum in Rails"
|
||||||
t.index ["study_group_id"], name: "index_study_group_memberships_on_study_group_id"
|
t.index ["study_group_id"], name: "index_study_group_memberships_on_study_group_id"
|
||||||
t.index ["user_type", "user_id"], name: "index_study_group_memberships_on_user"
|
t.index ["user_type", "user_id"], name: "index_study_group_memberships_on_user"
|
||||||
end
|
end
|
||||||
@ -465,6 +468,8 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.boolean "deleted"
|
t.boolean "deleted"
|
||||||
|
t.bigint "study_group_id"
|
||||||
|
t.index ["study_group_id"], name: "index_subscriptions_on_study_group_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "tags", id: :serial, force: :cascade do |t|
|
create_table "tags", id: :serial, force: :cascade do |t|
|
||||||
@ -563,6 +568,7 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
t.index ["user_type", "user_id"], name: "index_user_proxy_exercise_exercises_on_user"
|
t.index ["user_type", "user_id"], name: "index_user_proxy_exercise_exercises_on_user"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_foreign_key "authentication_tokens", "study_groups"
|
||||||
add_foreign_key "community_solution_contributions", "community_solution_locks"
|
add_foreign_key "community_solution_contributions", "community_solution_locks"
|
||||||
add_foreign_key "community_solution_contributions", "community_solutions"
|
add_foreign_key "community_solution_contributions", "community_solutions"
|
||||||
add_foreign_key "community_solution_contributions", "study_groups"
|
add_foreign_key "community_solution_contributions", "study_groups"
|
||||||
@ -573,6 +579,7 @@ ActiveRecord::Schema.define(version: 2022_07_21_131946) do
|
|||||||
add_foreign_key "exercise_tips", "tips"
|
add_foreign_key "exercise_tips", "tips"
|
||||||
add_foreign_key "remote_evaluation_mappings", "study_groups"
|
add_foreign_key "remote_evaluation_mappings", "study_groups"
|
||||||
add_foreign_key "submissions", "study_groups"
|
add_foreign_key "submissions", "study_groups"
|
||||||
|
add_foreign_key "subscriptions", "study_groups"
|
||||||
add_foreign_key "testrun_execution_environments", "execution_environments"
|
add_foreign_key "testrun_execution_environments", "execution_environments"
|
||||||
add_foreign_key "testrun_execution_environments", "testruns"
|
add_foreign_key "testrun_execution_environments", "testruns"
|
||||||
add_foreign_key "testrun_messages", "testruns"
|
add_foreign_key "testrun_messages", "testruns"
|
||||||
|
Reference in New Issue
Block a user