gitlab-org--gitlab-foss/lib/gitlab/background_migration/fix_pages_access_level.rb

128 lines
4.2 KiB
Ruby

# 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 < ActiveRecord::Base
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 they have `private` pages_access_level
# if access control is disabled, these projects currently behave as if they 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