diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-26 12:08:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-26 12:08:06 +0300 |
commit | 27c6c4bf061c3a2289ce4808b1b354535994d09d (patch) | |
tree | e973f10e40356141a4f19b94259b3b2f2b93b792 /app | |
parent | 47a2a65f346719a0b4441a28a7adcbe747173f30 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/stylesheets/components/related_items_list.scss | 18 | ||||
-rw-r--r-- | app/controllers/concerns/check_codeowner_rules.rb | 9 | ||||
-rw-r--r-- | app/controllers/projects/blob_controller.rb | 17 | ||||
-rw-r--r-- | app/finders/ci/runners_finder.rb | 4 | ||||
-rw-r--r-- | app/finders/issuable_finder.rb | 2 | ||||
-rw-r--r-- | app/graphql/mutations/merge_requests/create.rb | 63 | ||||
-rw-r--r-- | app/graphql/types/milestone_type.rb | 12 | ||||
-rw-r--r-- | app/graphql/types/mutation_type.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/featurable.rb | 99 | ||||
-rw-r--r-- | app/models/concerns/issuable.rb | 9 | ||||
-rw-r--r-- | app/models/milestone.rb | 4 | ||||
-rw-r--r-- | app/models/project_feature.rb | 106 |
12 files changed, 214 insertions, 130 deletions
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss index 61f971a3185..fd1108a7305 100644 --- a/app/assets/stylesheets/components/related_items_list.scss +++ b/app/assets/stylesheets/components/related_items_list.scss @@ -23,6 +23,11 @@ $item-remove-button-space: 42px; .sortable-link { white-space: normal; } + + .item-assignees .avatar { + height: $gl-padding; + width: $gl-padding; + } } .item-body { @@ -276,10 +281,6 @@ $item-remove-button-space: 42px; /* Small devices (landscape phones, 768px and up) */ @include media-breakpoint-up(md) { - .item-body .item-contents { - max-width: 95%; - } - .related-items-tree .item-contents, .item-body .item-title { max-width: 100%; @@ -348,6 +349,11 @@ $item-remove-button-space: 42px; } .item-assignees { + .avatar { + height: $gl-padding-24; + width: $gl-padding-24; + } + .avatar-counter { height: $gl-padding-24; min-width: $gl-padding-24; @@ -366,6 +372,10 @@ $item-remove-button-space: 42px; .sortable-link { line-height: 1.3; } + + .item-info-area { + flex-basis: auto; + } } @media only screen and (min-width: 1500px) { diff --git a/app/controllers/concerns/check_codeowner_rules.rb b/app/controllers/concerns/check_codeowner_rules.rb deleted file mode 100644 index 87947a356f7..00000000000 --- a/app/controllers/concerns/check_codeowner_rules.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -module CheckCodeownerRules - extend ActiveSupport::Concern - - def codeowners_check_error(project, branch_name, paths) - ::Gitlab::CodeOwners::Validator.new(project, branch_name, paths).execute - end -end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index d044548e147..d35498260c6 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -9,7 +9,6 @@ class Projects::BlobController < Projects::ApplicationController include ActionView::Helpers::SanitizeHelper include RedirectsForMissingPathOnTree include SourcegraphDecorator - include CheckCodeownerRules prepend_before_action :authenticate_user!, only: [:edit] @@ -29,7 +28,6 @@ class Projects::BlobController < Projects::ApplicationController before_action :editor_variables, except: [:show, :preview, :diff] before_action :validate_diff_params, only: :diff before_action :set_last_commit_sha, only: [:edit, :update] - before_action :validate_codeowner_rules, only: [:create, :update] before_action only: :show do push_frontend_feature_flag(:code_navigation, @project) @@ -118,18 +116,7 @@ class Projects::BlobController < Projects::ApplicationController private - def validate_codeowner_rules - return if params[:file_path].blank? - - codeowners_error = codeowners_check_error(@project, @branch_name, params[:file_path]) - - if codeowners_error.present? - flash.now[:alert] = codeowners_error - view = params[:action] == 'update' ? :edit : :new - - render view - end - end + attr_reader :branch_name def blob @blob ||= @repository.blob_at(@commit.id, @path) @@ -270,3 +257,5 @@ class Projects::BlobController < Projects::ApplicationController params.permit(:full, :since, :to, :bottom, :unfold, :offset, :indent) end end + +Projects::BlobController.prepend_if_ee('EE::Projects::BlobController') diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb index 54d9d9522e0..1b76211c524 100644 --- a/app/finders/ci/runners_finder.rb +++ b/app/finders/ci/runners_finder.rb @@ -52,9 +52,9 @@ module Ci raise Gitlab::Access::AccessDeniedError unless can?(@current_user, :admin_group, @group) # Getting all runners from the group itself and all its descendants - descentant_projects = Project.for_group_and_its_subgroups(@group) + descendant_projects = Project.for_group_and_its_subgroups(@group) - @runners = Ci::Runner.belonging_to_group_or_project(@group.self_and_descendants, descentant_projects) + @runners = Ci::Runner.belonging_to_group_or_project(@group.self_and_descendants, descendant_projects) end def filter_by_status! diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 7014f2ec205..5cdc22fd873 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -451,7 +451,7 @@ class IssuableFinder if params.filter_by_no_label? items.without_label elsif params.filter_by_any_label? - items.any_label + items.any_label(params[:sort]) else items.with_label(params.label_names, params[:sort]) end diff --git a/app/graphql/mutations/merge_requests/create.rb b/app/graphql/mutations/merge_requests/create.rb new file mode 100644 index 00000000000..95d6fb100e7 --- /dev/null +++ b/app/graphql/mutations/merge_requests/create.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class Create < BaseMutation + include Mutations::ResolvesProject + + graphql_name 'MergeRequestCreate' + + argument :project_path, GraphQL::ID_TYPE, + required: true, + description: 'Project full path the merge request is associated with' + + argument :title, GraphQL::STRING_TYPE, + required: true, + description: copy_field_description(Types::MergeRequestType, :title) + + argument :source_branch, GraphQL::STRING_TYPE, + required: true, + description: copy_field_description(Types::MergeRequestType, :source_branch) + + argument :target_branch, GraphQL::STRING_TYPE, + required: true, + description: copy_field_description(Types::MergeRequestType, :target_branch) + + argument :description, GraphQL::STRING_TYPE, + required: false, + description: copy_field_description(Types::MergeRequestType, :description) + + field :merge_request, + Types::MergeRequestType, + null: true, + description: 'The merge request after mutation' + + authorize :create_merge_request_from + + def resolve(project_path:, title:, source_branch:, target_branch:, description: nil) + project = authorized_find!(full_path: project_path) + + attributes = { + title: title, + source_branch: source_branch, + target_branch: target_branch, + author_id: current_user.id, + description: description + } + + merge_request = ::MergeRequests::CreateService.new(project, current_user, attributes).execute + + { + merge_request: merge_request.valid? ? merge_request : nil, + errors: errors_on_object(merge_request) + } + end + + private + + def find_object(full_path:) + resolve_project(full_path: full_path) + end + end + end +end diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb index 900f8c6f01d..99bd6e819d6 100644 --- a/app/graphql/types/milestone_type.rb +++ b/app/graphql/types/milestone_type.rb @@ -35,5 +35,17 @@ module Types field :updated_at, Types::TimeType, null: false, description: 'Timestamp of last milestone update' + + field :project_milestone, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates if milestone is at project level', + method: :project_milestone? + + field :group_milestone, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates if milestone is at group level', + method: :group_milestone? + + field :subgroup_milestone, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates if milestone is at subgroup level', + method: :subgroup_milestone? end end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index aeff84b83b8..ae5469ba5b2 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -16,6 +16,7 @@ module Types mount_mutation Mutations::Issues::SetConfidential mount_mutation Mutations::Issues::SetDueDate mount_mutation Mutations::Issues::Update + mount_mutation Mutations::MergeRequests::Create mount_mutation Mutations::MergeRequests::SetLabels mount_mutation Mutations::MergeRequests::SetLocked mount_mutation Mutations::MergeRequests::SetMilestone diff --git a/app/models/concerns/featurable.rb b/app/models/concerns/featurable.rb new file mode 100644 index 00000000000..60aa46ce04c --- /dev/null +++ b/app/models/concerns/featurable.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +# == Featurable concern +# +# This concern adds features (tools) functionality to Project and Group +# To enable features you need to call `set_available_features` +# +# Example: +# +# class ProjectFeature +# include Featurable +# set_available_features %i(wiki merge_request) + +module Featurable + extend ActiveSupport::Concern + + # Can be enabled only for members, everyone or disabled + # Access control is made only for non private containers. + # + # Permission levels: + # + # 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) + DISABLED = 0 + PRIVATE = 10 + ENABLED = 20 + PUBLIC = 30 + + STRING_OPTIONS = HashWithIndifferentAccess.new({ + 'disabled' => DISABLED, + 'private' => PRIVATE, + 'enabled' => ENABLED, + 'public' => PUBLIC + }).freeze + + class_methods do + def set_available_features(available_features = []) + @available_features = available_features + + class_eval do + available_features.each do |feature| + define_method("#{feature}_enabled?") do + public_send("#{feature}_access_level") > DISABLED # rubocop:disable GitlabSecurity/PublicSend + end + end + end + end + + def available_features + @available_features + end + + def access_level_attribute(feature) + feature = ensure_feature!(feature) + + "#{feature}_access_level".to_sym + end + + def quoted_access_level_column(feature) + attribute = connection.quote_column_name(access_level_attribute(feature)) + table = connection.quote_table_name(table_name) + + "#{table}.#{attribute}" + end + + def access_level_from_str(level) + STRING_OPTIONS.fetch(level) + end + + def str_from_access_level(level) + STRING_OPTIONS.key(level) + end + + def ensure_feature!(feature) + feature = feature.model_name.plural if feature.respond_to?(:model_name) + feature = feature.to_sym + raise ArgumentError, "invalid feature: #{feature}" unless available_features.include?(feature) + + feature + end + end + + def access_level(feature) + public_send(self.class.access_level_attribute(feature)) # rubocop:disable GitlabSecurity/PublicSend + end + + 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) + + get_permission(user, feature) + end + + def string_access_level(feature) + self.class.str_from_access_level(access_level(feature)) + end +end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index a1b14dca4ac..1407a380978 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -139,7 +139,6 @@ module Issuable scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) } scope :with_label_ids, ->(label_ids) { joins(:label_links).where(label_links: { label_id: label_ids }) } - scope :any_label, -> { joins(:label_links).distinct } scope :join_project, -> { joins(:project) } scope :inc_notes_with_associations, -> { includes(notes: [:project, :author, :award_emoji]) } scope :references_project, -> { references(:project) } @@ -316,6 +315,14 @@ module Issuable end end + def any_label(sort = nil) + if sort + joins(:label_links).group(*grouping_columns(sort)) + else + joins(:label_links).distinct + end + end + # Includes table keys in group by clause when sorting # preventing errors in postgres # diff --git a/app/models/milestone.rb b/app/models/milestone.rb index b5e4f62792e..ba9635897a3 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -179,6 +179,10 @@ class Milestone < ApplicationRecord end end + def subgroup_milestone? + group_milestone? && parent.subgroup? + end + private def milestone_format_reference(format = :iid) diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 9201cd24d66..b3ebcbd4b17 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -1,51 +1,16 @@ # frozen_string_literal: true class ProjectFeature < ApplicationRecord - # == Project features permissions - # - # Grants access level to project tools - # - # Tools can be enabled only for users, everyone or disabled - # Access control is made only for non private projects - # - # levels: - # - # 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 + include Featurable FEATURES = %i(issues forking merge_requests wiki snippets builds repository pages metrics_dashboard).freeze + + set_available_features(FEATURES) + PRIVATE_FEATURES_MIN_ACCESS_LEVEL = { merge_requests: Gitlab::Access::REPORTER, metrics_dashboard: Gitlab::Access::REPORTER }.freeze PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT = { repository: Gitlab::Access::REPORTER }.freeze - STRING_OPTIONS = HashWithIndifferentAccess.new({ - 'disabled' => DISABLED, - 'private' => PRIVATE, - 'enabled' => ENABLED, - 'public' => PUBLIC - }).freeze class << self - def access_level_attribute(feature) - feature = ensure_feature!(feature) - - "#{feature}_access_level".to_sym - end - - def quoted_access_level_column(feature) - attribute = connection.quote_column_name(access_level_attribute(feature)) - table = connection.quote_table_name(table_name) - - "#{table}.#{attribute}" - end - def required_minimum_access_level(feature) feature = ensure_feature!(feature) @@ -60,24 +25,6 @@ class ProjectFeature < ApplicationRecord required_minimum_access_level(feature) end end - - def access_level_from_str(level) - STRING_OPTIONS.fetch(level) - end - - def str_from_access_level(level) - STRING_OPTIONS.key(level) - end - - private - - def ensure_feature!(feature) - feature = feature.model_name.plural if feature.respond_to?(:model_name) - feature = feature.to_sym - raise ArgumentError, "invalid project feature: #{feature}" unless FEATURES.include?(feature) - - feature - end end # Default scopes force us to unscope here since a service may need to check @@ -107,45 +54,6 @@ class ProjectFeature < ApplicationRecord end end - 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) - - get_permission(user, feature) - end - - def access_level(feature) - public_send(ProjectFeature.access_level_attribute(feature)) # rubocop:disable GitlabSecurity/PublicSend - end - - def string_access_level(feature) - ProjectFeature.str_from_access_level(access_level(feature)) - end - - def builds_enabled? - builds_access_level > DISABLED - end - - def wiki_enabled? - wiki_access_level > DISABLED - end - - def merge_requests_enabled? - merge_requests_access_level > DISABLED - end - - def forking_enabled? - forking_access_level > DISABLED - end - - def issues_enabled? - issues_access_level > DISABLED - end - - def pages_enabled? - pages_access_level > DISABLED - end - def public_pages? return true unless Gitlab.config.pages.access_control @@ -164,7 +72,7 @@ class ProjectFeature < ApplicationRecord # which cannot be higher than repository access level def repository_children_level validator = lambda do |field| - level = public_send(field) || ProjectFeature::ENABLED # rubocop:disable GitlabSecurity/PublicSend + level = public_send(field) || ENABLED # rubocop:disable GitlabSecurity/PublicSend not_allowed = level > repository_access_level self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed end @@ -175,8 +83,8 @@ class ProjectFeature < ApplicationRecord # 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 + level = public_send(field) || ENABLED # rubocop:disable GitlabSecurity/PublicSend + not_allowed = level > ENABLED self.errors.add(field, "cannot have public visibility level") if not_allowed end |