diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue | 40 | ||||
-rw-r--r-- | app/controllers/projects_controller.rb | 1 | ||||
-rw-r--r-- | app/graphql/types/permission_types/project.rb | 2 | ||||
-rw-r--r-- | app/helpers/projects_helper.rb | 6 | ||||
-rw-r--r-- | app/models/project.rb | 12 | ||||
-rw-r--r-- | app/models/project_feature.rb | 28 | ||||
-rw-r--r-- | app/policies/project_policy.rb | 5 | ||||
-rw-r--r-- | app/services/projects/update_pages_configuration_service.rb | 8 | ||||
-rw-r--r-- | app/services/projects/update_service.rb | 10 |
9 files changed, 100 insertions, 12 deletions
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index 875f6928bed..a16f7e6b77c 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -52,6 +52,21 @@ required: false, default: '', }, + pagesAvailable: { + type: Boolean, + required: false, + default: false, + }, + pagesAccessControlEnabled: { + type: Boolean, + required: false, + default: false, + }, + pagesHelpPath: { + type: String, + required: false, + default: '', + }, }, data() { @@ -64,6 +79,7 @@ buildsAccessLevel: 20, wikiAccessLevel: 20, snippetsAccessLevel: 20, + pagesAccessLevel: 20, containerRegistryEnabled: true, lfsEnabled: true, requestAccessEnabled: true, @@ -90,6 +106,13 @@ ); }, + pagesFeatureAccessLevelOptions() { + if (this.visibilityLevel !== visibilityOptions.PUBLIC) { + return this.featureAccessLevelOptions.concat([[30, 'Everyone']]); + } + return this.featureAccessLevelOptions; + }, + repositoryEnabled() { return this.repositoryAccessLevel > 0; }, @@ -109,6 +132,10 @@ this.buildsAccessLevel = Math.min(10, this.buildsAccessLevel); this.wikiAccessLevel = Math.min(10, this.wikiAccessLevel); this.snippetsAccessLevel = Math.min(10, this.snippetsAccessLevel); + if (this.pagesAccessLevel === 20) { + // When from Internal->Private narrow access for only members + this.pagesAccessLevel = 10; + } this.highlightChanges(); } else if (oldValue === visibilityOptions.PRIVATE) { // if changing away from private, make enabled features more permissive @@ -118,6 +145,7 @@ if (this.buildsAccessLevel > 0) this.buildsAccessLevel = 20; if (this.wikiAccessLevel > 0) this.wikiAccessLevel = 20; if (this.snippetsAccessLevel > 0) this.snippetsAccessLevel = 20; + if (this.pagesAccessLevel === 10) this.pagesAccessLevel = 20; this.highlightChanges(); } }, @@ -323,6 +351,18 @@ name="project[project_feature_attributes][snippets_access_level]" /> </project-setting-row> + <project-setting-row + v-if="pagesAvailable && pagesAccessControlEnabled" + :help-path="pagesHelpPath" + label="Pages" + help-text="Static website for the project." + > + <project-feature-setting + v-model="pagesAccessLevel" + :options="pagesFeatureAccessLevelOptions" + name="project[project_feature_attributes][pages_access_level]" + /> + </project-setting-row> </div> </div> </template> diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index a9417369ca2..ee438e160f2 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -366,6 +366,7 @@ class ProjectsController < Projects::ApplicationController repository_access_level snippets_access_level wiki_access_level + pages_access_level ] ] end diff --git a/app/graphql/types/permission_types/project.rb b/app/graphql/types/permission_types/project.rb index 066ce64a254..ab37c282fe5 100644 --- a/app/graphql/types/permission_types/project.rb +++ b/app/graphql/types/permission_types/project.rb @@ -16,7 +16,7 @@ module Types :create_deployment, :push_to_delete_protected_branch, :admin_wiki, :admin_project, :update_pages, :admin_remote_mirror, :create_label, :update_wiki, :destroy_wiki, - :create_pages, :destroy_pages + :create_pages, :destroy_pages, :read_pages_content end end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8b17e6ef75d..0016f89db5c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -454,6 +454,7 @@ module ProjectsHelper buildsAccessLevel: feature.builds_access_level, wikiAccessLevel: feature.wiki_access_level, snippetsAccessLevel: feature.snippets_access_level, + pagesAccessLevel: feature.pages_access_level, containerRegistryEnabled: !!project.container_registry_enabled, lfsEnabled: !!project.lfs_enabled } @@ -468,7 +469,10 @@ module ProjectsHelper registryAvailable: Gitlab.config.registry.enabled, registryHelpPath: help_page_path('user/project/container_registry'), lfsAvailable: Gitlab.config.lfs.enabled, - lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + lfsHelpPath: help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs'), + pagesAvailable: Gitlab.config.pages.enabled, + pagesAccessControlEnabled: Gitlab.config.pages.access_control, + pagesHelpPath: help_page_path('user/project/pages/index.md') } end diff --git a/app/models/project.rb b/app/models/project.rb index 59f088156c7..dc2732cc6c2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -55,8 +55,8 @@ class Project < ActiveRecord::Base cache_markdown_field :description, pipeline: :description delegate :feature_available?, :builds_enabled?, :wiki_enabled?, - :merge_requests_enabled?, :issues_enabled?, to: :project_feature, - allow_nil: true + :merge_requests_enabled?, :issues_enabled?, :pages_enabled?, :public_pages?, + to: :project_feature, allow_nil: true delegate :base_dir, :disk_path, :ensure_storage_path_exists, to: :storage @@ -356,7 +356,7 @@ class Project < ActiveRecord::Base # "enabled" here means "not disabled". It includes private features! scope :with_feature_enabled, ->(feature) { access_level_attribute = ProjectFeature.access_level_attribute(feature) - with_project_feature.where(project_features: { access_level_attribute => [nil, ProjectFeature::PRIVATE, ProjectFeature::ENABLED] }) + with_project_feature.where(project_features: { access_level_attribute => [nil, ProjectFeature::PRIVATE, ProjectFeature::ENABLED, ProjectFeature::PUBLIC] }) } # Picks a feature where the level is exactly that given. @@ -418,15 +418,15 @@ class Project < ActiveRecord::Base end end - # project features may be "disabled", "internal" or "enabled". If "internal", + # project features may be "disabled", "internal", "enabled" or "public". If "internal", # they are only available to team members. This scope returns projects where - # the feature is either enabled, or internal with permission for the user. + # the feature is either public, enabled, or internal with permission for the user. # # This method uses an optimised version of `with_feature_access_level` for # logged in users to more efficiently get private projects with the given # feature. def self.with_feature_available_for_user(feature, user) - visible = [nil, ProjectFeature::ENABLED] + visible = [nil, ProjectFeature::ENABLED, ProjectFeature::PUBLIC] if user&.admin? with_feature_enabled(feature) diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 754c2461d23..39f2b8fe0de 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -13,14 +13,16 @@ class ProjectFeature < ActiveRecord::Base # Disabled: not enabled for anyone # Private: enabled only for team members # Enabled: enabled for everyone able to access the project + # Public: enabled for everyone (only allowed for pages) # # Permission levels DISABLED = 0 PRIVATE = 10 ENABLED = 20 + PUBLIC = 30 - FEATURES = %i(issues merge_requests wiki snippets builds repository).freeze + FEATURES = %i(issues merge_requests wiki snippets builds repository pages).freeze class << self def access_level_attribute(feature) @@ -46,6 +48,7 @@ class ProjectFeature < ActiveRecord::Base validates :project, presence: true validate :repository_children_level + validate :allowed_access_levels default_value_for :builds_access_level, value: ENABLED, allows_nil: false default_value_for :issues_access_level, value: ENABLED, allows_nil: false @@ -81,6 +84,16 @@ class ProjectFeature < ActiveRecord::Base issues_access_level > DISABLED end + def pages_enabled? + pages_access_level > DISABLED + end + + def public_pages? + return true unless Gitlab.config.pages.access_control + + pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public? + end + private # Validates builds and merge requests access level @@ -95,6 +108,17 @@ class ProjectFeature < ActiveRecord::Base %i(merge_requests_access_level builds_access_level).each(&validator) end + # Validates access level for other than pages cannot be PUBLIC + def allowed_access_levels + validator = lambda do |field| + level = public_send(field) || ProjectFeature::ENABLED # rubocop:disable GitlabSecurity/PublicSend + not_allowed = level > ProjectFeature::ENABLED + self.errors.add(field, "cannot have public visibility level") if not_allowed + end + + (FEATURES - %i(pages)).each {|f| validator.call("#{f}_access_level")} + end + def get_permission(user, level) case level when DISABLED @@ -103,6 +127,8 @@ class ProjectFeature < ActiveRecord::Base user && (project.team.member?(user) || user.full_private_access?) when ENABLED true + when PUBLIC + true else true end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index f2c246cd969..a76a083bceb 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -110,6 +110,7 @@ class ProjectPolicy < BasePolicy snippets wiki builds + pages ] features.each do |f| @@ -167,6 +168,7 @@ class ProjectPolicy < BasePolicy enable :upload_file enable :read_cycle_analytics enable :award_emoji + enable :read_pages_content end # These abilities are not allowed to admins that are not members of the project, @@ -286,6 +288,8 @@ class ProjectPolicy < BasePolicy prevent(*create_read_update_admin_destroy(:merge_request)) end + rule { pages_disabled }.prevent :read_pages_content + rule { issues_disabled & merge_requests_disabled }.policy do prevent(*create_read_update_admin_destroy(:label)) prevent(*create_read_update_admin_destroy(:milestone)) @@ -345,6 +349,7 @@ class ProjectPolicy < BasePolicy enable :download_code enable :download_wiki_code enable :read_cycle_analytics + enable :read_pages_content # NOTE: may be overridden by IssuePolicy enable :read_issue diff --git a/app/services/projects/update_pages_configuration_service.rb b/app/services/projects/update_pages_configuration_service.rb index efbd4c7b323..abf40b3ad7a 100644 --- a/app/services/projects/update_pages_configuration_service.rb +++ b/app/services/projects/update_pages_configuration_service.rb @@ -21,7 +21,9 @@ module Projects def pages_config { domains: pages_domains_config, - https_only: project.pages_https_only? + https_only: project.pages_https_only?, + id: project.project_id, + access_control: !project.public_pages? } end @@ -31,7 +33,9 @@ module Projects domain: domain.domain, certificate: domain.certificate, key: domain.key, - https_only: project.pages_https_only? && domain.https? + https_only: project.pages_https_only? && domain.https?, + id: project.project_id, + access_control: !project.public_pages? } end end diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index d6d9bacf232..f25a4e30938 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -72,7 +72,11 @@ module Projects system_hook_service.execute_hooks_for(project, :update) end - update_pages_config if changing_pages_https_only? + update_pages_config if changing_pages_related_config? + end + + def changing_pages_related_config? + changing_pages_https_only? || changing_pages_access_level? end def update_failed! @@ -102,6 +106,10 @@ module Projects params.dig(:project_feature_attributes, :wiki_access_level).to_i > ProjectFeature::DISABLED end + def changing_pages_access_level? + params.dig(:project_feature_attributes, :pages_access_level) + end + def ensure_wiki_exists ProjectWiki.new(project, project.owner).wiki rescue ProjectWiki::CouldNotCreateWikiError |