Loading app/models/project_feature.rb +2 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ def ensure_feature!(feature) default_value_for :wiki_access_level, value: ENABLED, allows_nil: false default_value_for :repository_access_level, value: ENABLED, allows_nil: false default_value_for(:pages_access_level, allows_nil: false) { |feature| feature.project&.public? ? ENABLED : PRIVATE } def feature_available?(feature, user) # This feature might not be behind a feature flag at all, so default to true return false unless ::Feature.enabled?(feature, user, default_enabled: true) Loading db/post_migrate/20190703185326_fix_wrong_pages_access_level.rb 0 → 100644 +28 −0 Original line number Diff line number Diff line # frozen_string_literal: true class FixWrongPagesAccessLevel < ActiveRecord::Migration[5.1] include Gitlab::Database::MigrationHelpers DOWNTIME = false MIGRATION = 'FixPagesAccessLevel' BATCH_SIZE = 20_000 BATCH_TIME = 2.minutes disable_ddl_transaction! class ProjectFeature < ActiveRecord::Base include ::EachBatch self.table_name = 'project_features' self.inheritance_column = :_type_disabled end def up queue_background_migration_jobs_by_range_at_intervals( ProjectFeature, MIGRATION, BATCH_TIME, batch_size: BATCH_SIZE) end end db/post_migrate/20190715114644_drop_project_features_pages_access_level_default.rb 0 → 100644 +12 −0 Original line number Diff line number Diff line # frozen_string_literal: true class DropProjectFeaturesPagesAccessLevelDefault < ActiveRecord::Migration[5.1] include Gitlab::Database::MigrationHelpers DOWNTIME = false ENABLED_VALUE = 20 def change change_column_default :project_features, :pages_access_level, from: ENABLED_VALUE, to: nil end end db/schema.rb +2 −2 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 2019_07_03_130053) do ActiveRecord::Schema.define(version: 2019_07_15_114644) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" Loading Loading @@ -2507,7 +2507,7 @@ t.datetime "created_at" t.datetime "updated_at" t.integer "repository_access_level", default: 20, null: false t.integer "pages_access_level", default: 20, null: false t.integer "pages_access_level", null: false t.index ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree end Loading lib/gitlab/background_migration/fix_pages_access_level.rb 0 → 100644 +128 −0 Original line number Diff line number Diff line # frozen_string_literal: true module Gitlab module BackgroundMigration # corrects stored pages access level on db depending on project visibility class FixPagesAccessLevel # Copy routable here to avoid relying on application logic module Routable def build_full_path if parent && path parent.build_full_path + '/' + path else path end end end # Namespace class Namespace < ApplicationRecord self.table_name = 'namespaces' self.inheritance_column = :_type_disabled include Routable belongs_to :parent, class_name: "Namespace" end # Project class Project < ActiveRecord::Base self.table_name = 'projects' self.inheritance_column = :_type_disabled include Routable belongs_to :namespace alias_method :parent, :namespace alias_attribute :parent_id, :namespace_id PRIVATE = 0 INTERNAL = 10 PUBLIC = 20 def pages_deployed? Dir.exist?(public_pages_path) end def public_pages_path File.join(pages_path, 'public') end def pages_path # TODO: when we migrate Pages to work with new storage types, change here to use disk_path File.join(Settings.pages.path, build_full_path) end end # ProjectFeature class ProjectFeature < ActiveRecord::Base include ::EachBatch self.table_name = 'project_features' belongs_to :project PRIVATE = 10 ENABLED = 20 PUBLIC = 30 end def perform(start_id, stop_id) fix_public_access_level(start_id, stop_id) make_internal_projects_public(start_id, stop_id) fix_private_access_level(start_id, stop_id) end private def access_control_is_enabled @access_control_is_enabled = Gitlab.config.pages.access_control end # Public projects are allowed to have only enabled pages_access_level # which is equivalent to public def fix_public_access_level(start_id, stop_id) project_features(start_id, stop_id, ProjectFeature::PUBLIC, Project::PUBLIC).each_batch do |features| features.update_all(pages_access_level: ProjectFeature::ENABLED) end end # If access control is disabled and project has pages deployed # project will become unavailable when access control will become enabled # we make these projects public to avoid negative surprise to user def make_internal_projects_public(start_id, stop_id) return if access_control_is_enabled project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::INTERNAL).find_each do |project_feature| next unless project_feature.project.pages_deployed? project_feature.update(pages_access_level: ProjectFeature::PUBLIC) end end # Private projects are not allowed to have enabled access level, only `private` and `public` # If access control is enabled, these projects currently behave as if the have `private` pages_access_level # if access control is disabled, these projects currently behave as if the have `public` pages_access_level # so we preserve this behaviour for projects with pages already deployed # for project without pages we always set `private` access_level def fix_private_access_level(start_id, stop_id) project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::PRIVATE).find_each do |project_feature| if access_control_is_enabled project_feature.update!(pages_access_level: ProjectFeature::PRIVATE) else fixed_access_level = project_feature.project.pages_deployed? ? ProjectFeature::PUBLIC : ProjectFeature::PRIVATE project_feature.update!(pages_access_level: fixed_access_level) end end end def project_features(start_id, stop_id, pages_access_level, project_visibility_level) ProjectFeature.where(id: start_id..stop_id).joins(:project) .where(pages_access_level: pages_access_level) .where(projects: { visibility_level: project_visibility_level }) end end end end Loading
app/models/project_feature.rb +2 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ def ensure_feature!(feature) default_value_for :wiki_access_level, value: ENABLED, allows_nil: false default_value_for :repository_access_level, value: ENABLED, allows_nil: false default_value_for(:pages_access_level, allows_nil: false) { |feature| feature.project&.public? ? ENABLED : PRIVATE } def feature_available?(feature, user) # This feature might not be behind a feature flag at all, so default to true return false unless ::Feature.enabled?(feature, user, default_enabled: true) Loading
db/post_migrate/20190703185326_fix_wrong_pages_access_level.rb 0 → 100644 +28 −0 Original line number Diff line number Diff line # frozen_string_literal: true class FixWrongPagesAccessLevel < ActiveRecord::Migration[5.1] include Gitlab::Database::MigrationHelpers DOWNTIME = false MIGRATION = 'FixPagesAccessLevel' BATCH_SIZE = 20_000 BATCH_TIME = 2.minutes disable_ddl_transaction! class ProjectFeature < ActiveRecord::Base include ::EachBatch self.table_name = 'project_features' self.inheritance_column = :_type_disabled end def up queue_background_migration_jobs_by_range_at_intervals( ProjectFeature, MIGRATION, BATCH_TIME, batch_size: BATCH_SIZE) end end
db/post_migrate/20190715114644_drop_project_features_pages_access_level_default.rb 0 → 100644 +12 −0 Original line number Diff line number Diff line # frozen_string_literal: true class DropProjectFeaturesPagesAccessLevelDefault < ActiveRecord::Migration[5.1] include Gitlab::Database::MigrationHelpers DOWNTIME = false ENABLED_VALUE = 20 def change change_column_default :project_features, :pages_access_level, from: ENABLED_VALUE, to: nil end end
db/schema.rb +2 −2 Original line number Diff line number Diff line Loading @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 2019_07_03_130053) do ActiveRecord::Schema.define(version: 2019_07_15_114644) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" Loading Loading @@ -2507,7 +2507,7 @@ t.datetime "created_at" t.datetime "updated_at" t.integer "repository_access_level", default: 20, null: false t.integer "pages_access_level", default: 20, null: false t.integer "pages_access_level", null: false t.index ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree end Loading
lib/gitlab/background_migration/fix_pages_access_level.rb 0 → 100644 +128 −0 Original line number Diff line number Diff line # frozen_string_literal: true module Gitlab module BackgroundMigration # corrects stored pages access level on db depending on project visibility class FixPagesAccessLevel # Copy routable here to avoid relying on application logic module Routable def build_full_path if parent && path parent.build_full_path + '/' + path else path end end end # Namespace class Namespace < ApplicationRecord self.table_name = 'namespaces' self.inheritance_column = :_type_disabled include Routable belongs_to :parent, class_name: "Namespace" end # Project class Project < ActiveRecord::Base self.table_name = 'projects' self.inheritance_column = :_type_disabled include Routable belongs_to :namespace alias_method :parent, :namespace alias_attribute :parent_id, :namespace_id PRIVATE = 0 INTERNAL = 10 PUBLIC = 20 def pages_deployed? Dir.exist?(public_pages_path) end def public_pages_path File.join(pages_path, 'public') end def pages_path # TODO: when we migrate Pages to work with new storage types, change here to use disk_path File.join(Settings.pages.path, build_full_path) end end # ProjectFeature class ProjectFeature < ActiveRecord::Base include ::EachBatch self.table_name = 'project_features' belongs_to :project PRIVATE = 10 ENABLED = 20 PUBLIC = 30 end def perform(start_id, stop_id) fix_public_access_level(start_id, stop_id) make_internal_projects_public(start_id, stop_id) fix_private_access_level(start_id, stop_id) end private def access_control_is_enabled @access_control_is_enabled = Gitlab.config.pages.access_control end # Public projects are allowed to have only enabled pages_access_level # which is equivalent to public def fix_public_access_level(start_id, stop_id) project_features(start_id, stop_id, ProjectFeature::PUBLIC, Project::PUBLIC).each_batch do |features| features.update_all(pages_access_level: ProjectFeature::ENABLED) end end # If access control is disabled and project has pages deployed # project will become unavailable when access control will become enabled # we make these projects public to avoid negative surprise to user def make_internal_projects_public(start_id, stop_id) return if access_control_is_enabled project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::INTERNAL).find_each do |project_feature| next unless project_feature.project.pages_deployed? project_feature.update(pages_access_level: ProjectFeature::PUBLIC) end end # Private projects are not allowed to have enabled access level, only `private` and `public` # If access control is enabled, these projects currently behave as if the have `private` pages_access_level # if access control is disabled, these projects currently behave as if the have `public` pages_access_level # so we preserve this behaviour for projects with pages already deployed # for project without pages we always set `private` access_level def fix_private_access_level(start_id, stop_id) project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::PRIVATE).find_each do |project_feature| if access_control_is_enabled project_feature.update!(pages_access_level: ProjectFeature::PRIVATE) else fixed_access_level = project_feature.project.pages_deployed? ? ProjectFeature::PUBLIC : ProjectFeature::PRIVATE project_feature.update!(pages_access_level: fixed_access_level) end end end def project_features(start_id, stop_id, pages_access_level, project_visibility_level) ProjectFeature.where(id: start_id..stop_id).joins(:project) .where(pages_access_level: pages_access_level) .where(projects: { visibility_level: project_visibility_level }) end end end end