1# frozen_string_literal: true 2 3module Gitlab 4 module BackgroundMigration 5 # corrects stored pages access level on db depending on project visibility 6 class FixPagesAccessLevel 7 # Copy routable here to avoid relying on application logic 8 module Routable 9 def build_full_path 10 if parent && path 11 parent.build_full_path + '/' + path 12 else 13 path 14 end 15 end 16 end 17 18 # Namespace 19 class Namespace < ActiveRecord::Base 20 self.table_name = 'namespaces' 21 self.inheritance_column = :_type_disabled 22 23 include Routable 24 25 belongs_to :parent, class_name: "Namespace" 26 end 27 28 # Project 29 class Project < ActiveRecord::Base 30 self.table_name = 'projects' 31 self.inheritance_column = :_type_disabled 32 33 include Routable 34 35 belongs_to :namespace 36 alias_method :parent, :namespace 37 alias_attribute :parent_id, :namespace_id 38 39 PRIVATE = 0 40 INTERNAL = 10 41 PUBLIC = 20 42 43 def pages_deployed? 44 Dir.exist?(public_pages_path) 45 end 46 47 def public_pages_path 48 File.join(pages_path, 'public') 49 end 50 51 def pages_path 52 # TODO: when we migrate Pages to work with new storage types, change here to use disk_path 53 File.join(Settings.pages.path, build_full_path) 54 end 55 end 56 57 # ProjectFeature 58 class ProjectFeature < ActiveRecord::Base 59 include ::EachBatch 60 61 self.table_name = 'project_features' 62 63 belongs_to :project 64 65 PRIVATE = 10 66 ENABLED = 20 67 PUBLIC = 30 68 end 69 70 def perform(start_id, stop_id) 71 fix_public_access_level(start_id, stop_id) 72 73 make_internal_projects_public(start_id, stop_id) 74 75 fix_private_access_level(start_id, stop_id) 76 end 77 78 private 79 80 def access_control_is_enabled 81 @access_control_is_enabled = Gitlab.config.pages.access_control 82 end 83 84 # Public projects are allowed to have only enabled pages_access_level 85 # which is equivalent to public 86 def fix_public_access_level(start_id, stop_id) 87 project_features(start_id, stop_id, ProjectFeature::PUBLIC, Project::PUBLIC).each_batch do |features| 88 features.update_all(pages_access_level: ProjectFeature::ENABLED) 89 end 90 end 91 92 # If access control is disabled and project has pages deployed 93 # project will become unavailable when access control will become enabled 94 # we make these projects public to avoid negative surprise to user 95 def make_internal_projects_public(start_id, stop_id) 96 return if access_control_is_enabled 97 98 project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::INTERNAL).find_each do |project_feature| 99 next unless project_feature.project.pages_deployed? 100 101 project_feature.update(pages_access_level: ProjectFeature::PUBLIC) 102 end 103 end 104 105 # Private projects are not allowed to have enabled access level, only `private` and `public` 106 # If access control is enabled, these projects currently behave as if they have `private` pages_access_level 107 # if access control is disabled, these projects currently behave as if they have `public` pages_access_level 108 # so we preserve this behaviour for projects with pages already deployed 109 # for project without pages we always set `private` access_level 110 def fix_private_access_level(start_id, stop_id) 111 project_features(start_id, stop_id, ProjectFeature::ENABLED, Project::PRIVATE).find_each do |project_feature| 112 if access_control_is_enabled 113 project_feature.update!(pages_access_level: ProjectFeature::PRIVATE) 114 else 115 fixed_access_level = project_feature.project.pages_deployed? ? ProjectFeature::PUBLIC : ProjectFeature::PRIVATE 116 project_feature.update!(pages_access_level: fixed_access_level) 117 end 118 end 119 end 120 121 def project_features(start_id, stop_id, pages_access_level, project_visibility_level) 122 ProjectFeature.where(id: start_id..stop_id).joins(:project) 123 .where(pages_access_level: pages_access_level) 124 .where(projects: { visibility_level: project_visibility_level }) 125 end 126 end 127 end 128end 129