diff --git a/app/controllers/projects/protected_tags/application_controller.rb b/app/controllers/projects/protected_tags/application_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..524b1c62d5585868e0ec2b5b3172059cf143af13 --- /dev/null +++ b/app/controllers/projects/protected_tags/application_controller.rb @@ -0,0 +1,7 @@ +class Projects::ProtectedTags::ApplicationController < Projects::ApplicationController + protected + + def load_protected_tag + @protected_tag = @project.protected_tags.find(params[:protected_tag_id]) + end +end diff --git a/app/controllers/projects/protected_tags/create_access_levels_controller.rb b/app/controllers/projects/protected_tags/create_access_levels_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..f7d3bab09bc2aa9d3bf268a0b7bb41b82129441c --- /dev/null +++ b/app/controllers/projects/protected_tags/create_access_levels_controller.rb @@ -0,0 +1,15 @@ +module Projects + module ProtectedTags + class CreateAccessLevelsController < ProtectedTags::ApplicationController + before_action :load_protected_tag, only: [:destroy] + + def destroy + @create_access_level = @protected_tag.create_access_levels.find(params[:id]) + @create_access_level.destroy + + redirect_to namespace_project_protected_tag_path(@project.namespace, @project, @protected_tag), + notice: "Successfully deleted. #{@create_access_level.humanize} will not be able to create this protected tag." + end + end + end +end diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb index 5b75b51148956d83ca37cd0ad9709fea402604d4..fdc8a89ce6cc17ab69481a5d45ee7a65328e5e05 100644 --- a/app/controllers/projects/settings/repository_controller.rb +++ b/app/controllers/projects/settings/repository_controller.rb @@ -31,6 +31,7 @@ module Projects { selected_merge_access_levels: @protected_branch.merge_access_levels.map { |access_level| access_level.user_id || access_level.access_level }, selected_push_access_levels: @protected_branch.push_access_levels.map { |access_level| access_level.user_id || access_level.access_level }, + selected_create_access_levels: @protected_tag.create_access_levels.map { |access_level| access_level.user_id || access_level.access_level }, create_access_levels: levels_for_dropdown(ProtectedTag::CreateAccessLevel), push_access_levels: levels_for_dropdown(ProtectedBranch::PushAccessLevel), merge_access_levels: levels_for_dropdown(ProtectedBranch::MergeAccessLevel) diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb index 62eaec2407f50fb020614715ecfae639ae8a8dbc..0572d399409e29ddc6c4ad1acc02998cb312e3c9 100644 --- a/app/models/concerns/protected_ref.rb +++ b/app/models/concerns/protected_ref.rb @@ -9,6 +9,21 @@ module ProtectedRef delegate :matching, :matches?, :wildcard?, to: :ref_matcher + def self.protected_ref_access_levels(*types) + types.each do |type| + has_many :"#{type}_access_levels", dependent: :destroy + + validates :"#{type}_access_levels", length: { minimum: 0 } + + accepts_nested_attributes_for :"#{type}_access_levels", allow_destroy: true + + # Returns access levels that grant the specified access type to the given user / group. + access_level_class = const_get("#{type}_access_level".camelize) + scope :"#{type}_access_by_user", -> (user) { access_level_class.joins(:protected_branch).where(protected_branch_id: self.ids).merge(access_level_class.by_user(user)) } + scope :"#{type}_access_by_group", -> (group) { access_level_class.joins(:protected_branch).where(protected_branch_id: self.ids).merge(access_level_class.by_group(group)) } + end + end + def self.protected_ref_accessible_to?(ref, user, action:) access_levels_for_ref(ref, action: action).any? do |access_level| access_level.check_access(user) diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 9079f4a17e9f27dcb49d35bd2181d138cb219082..ea0a06ad6f93a77bfda65fd302312fcb3e200a54 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -2,30 +2,7 @@ class ProtectedBranch < ActiveRecord::Base include Gitlab::ShellAdapter include ProtectedRef - has_many :merge_access_levels, dependent: :destroy - has_many :push_access_levels, dependent: :destroy - - validates :merge_access_levels, length: { minimum: 0 } - validates :push_access_levels, length: { minimum: 0 } - - accepts_nested_attributes_for :push_access_levels, allow_destroy: true - accepts_nested_attributes_for :merge_access_levels, allow_destroy: true - - # Returns all merge access levels (for protected branches in scope) that grant merge - # access to the given user. - scope :merge_access_by_user, -> (user) { MergeAccessLevel.joins(:protected_branch).where(protected_branch_id: self.ids).merge(MergeAccessLevel.by_user(user)) } - - # Returns all push access levels (for protected branches in scope) that grant push - # access to the given user. - scope :push_access_by_user, -> (user) { PushAccessLevel.joins(:protected_branch).where(protected_branch_id: self.ids).merge(PushAccessLevel.by_user(user)) } - - # Returns all merge access levels (for protected branches in scope) that grant merge - # access to the given group. - scope :merge_access_by_group, -> (group) { MergeAccessLevel.joins(:protected_branch).where(protected_branch_id: self.ids).merge(MergeAccessLevel.by_group(group)) } - - # Returns all push access levels (for protected branches in scope) that grant push - # access to the given group. - scope :push_access_by_group, -> (group) { PushAccessLevel.joins(:protected_branch).where(protected_branch_id: self.ids).merge(PushAccessLevel.by_group(group)) } + protected_ref_access_levels :merge, :push # Returns a hash were keys are types of push access levels (user, role), and # values are the number of access levels of the particular type. diff --git a/app/models/protected_tag.rb b/app/models/protected_tag.rb index 839640955162101d2bbca681d38a1c0a65b557d8..f38109c0e5275bdf55f7da13f1d4368f6cab0697 100644 --- a/app/models/protected_tag.rb +++ b/app/models/protected_tag.rb @@ -2,11 +2,7 @@ class ProtectedTag < ActiveRecord::Base include Gitlab::ShellAdapter include ProtectedRef - has_many :create_access_levels, dependent: :destroy - - validates :create_access_levels, length: { is: 1, message: "are restricted to a single instance per protected tag." } - - accepts_nested_attributes_for :create_access_levels + protected_ref_access_levels :create def self.protected?(project, ref_name) self.matching(ref_name, protected_refs: project.protected_tags).present?