Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f47c768fad
commit
5ad0cf2655
|
@ -13,7 +13,7 @@
|
|||
.default-before_script:
|
||||
before_script:
|
||||
- date
|
||||
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/'
|
||||
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/ qa/spec/ee/ qa/qa/specs/features/ee/ qa/qa/ee/ qa/qa/ee.rb'
|
||||
- export GOPATH=$CI_PROJECT_DIR/.go
|
||||
- mkdir -p $GOPATH
|
||||
- source scripts/utils.sh
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
paths:
|
||||
- vendor/ruby
|
||||
before_script:
|
||||
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/'
|
||||
- '[ "$FOSS_ONLY" = "1" ] && rm -rf ee/ qa/spec/ee/ qa/qa/specs/features/ee/ qa/qa/ee/ qa/qa/ee.rb'
|
||||
- cd qa/
|
||||
- bundle install --clean --jobs=$(nproc) --path=vendor --retry=3 --quiet
|
||||
- bundle check
|
||||
|
@ -50,6 +50,13 @@ qa:internal:
|
|||
script:
|
||||
- bundle exec rspec
|
||||
|
||||
qa:internal-foss:
|
||||
extends:
|
||||
- .qa-job-base
|
||||
- .only-ee-as-if-foss
|
||||
script:
|
||||
- bundle exec rspec
|
||||
|
||||
qa:selectors:
|
||||
extends: .qa-job-base
|
||||
script:
|
||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
|||
:action="action"
|
||||
/>
|
||||
<li v-if="hasMoreChildren" class="group-row">
|
||||
<a :href="parentGroup.relativePath" class="group-row-contents has-more-items">
|
||||
<a :href="parentGroup.relativePath" class="group-row-contents has-more-items py-2">
|
||||
<i class="fa fa-external-link" aria-hidden="true"> </i> {{ moreChildrenStats }}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -91,7 +91,7 @@ export default {
|
|||
<li :id="groupDomId" :class="rowClass" class="group-row" @click.stop="onClickRowGroup">
|
||||
<div
|
||||
:class="{ 'project-row-contents': !isGroup }"
|
||||
class="group-row-contents d-flex align-items-center"
|
||||
class="group-row-contents d-flex align-items-center py-2"
|
||||
>
|
||||
<div class="folder-toggle-wrap append-right-4 d-flex align-items-center">
|
||||
<item-caret :is-group-open="group.isOpen" />
|
||||
|
@ -104,7 +104,7 @@ export default {
|
|||
/>
|
||||
<div
|
||||
:class="{ 'd-sm-flex': !group.isChildrenLoading }"
|
||||
class="avatar-container rect-avatar s40 d-none flex-grow-0 flex-shrink-0 "
|
||||
class="avatar-container rect-avatar s32 d-none flex-grow-0 flex-shrink-0 "
|
||||
>
|
||||
<a :href="group.relativePath" class="no-expand">
|
||||
<img v-if="hasAvatar" :src="group.avatarUrl" class="avatar s40" />
|
||||
|
|
|
@ -47,7 +47,7 @@ export default {
|
|||
<template>
|
||||
<li :id="envId" :class="isOpenClass" class="group-row has-children">
|
||||
<div
|
||||
class="group-row-contents d-flex justify-content-end align-items-center"
|
||||
class="group-row-contents d-flex justify-content-end align-items-center py-2"
|
||||
role="button"
|
||||
@click.stop="toggleOpen"
|
||||
>
|
||||
|
|
|
@ -63,7 +63,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<li :id="name" class="group-row">
|
||||
<div class="group-row-contents" role="button" @click="openDetails">
|
||||
<div class="group-row-contents py-2" role="button" @click="openDetails">
|
||||
<p class="float-right text-right">
|
||||
<span>{{ image }}</span
|
||||
><br />
|
||||
|
|
|
@ -382,8 +382,6 @@ table.pipeline-project-metrics tr td {
|
|||
}
|
||||
|
||||
.group-row-contents {
|
||||
padding: $gl-padding;
|
||||
|
||||
&:hover {
|
||||
border-color: $blue-200;
|
||||
background-color: $blue-50;
|
||||
|
@ -410,13 +408,7 @@ table.pipeline-project-metrics tr td {
|
|||
|
||||
.title {
|
||||
margin-top: -$gl-padding-8; // negative margin required for flex-wrap
|
||||
font-size: $gl-font-size-large;
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
.title {
|
||||
font-size: $gl-font-size;
|
||||
}
|
||||
font-size: $gl-font-size;
|
||||
}
|
||||
|
||||
&.has-more-items {
|
||||
|
@ -483,7 +475,6 @@ table.pipeline-project-metrics tr td {
|
|||
|
||||
.last-updated {
|
||||
position: relative;
|
||||
right: 12px;
|
||||
min-width: 250px;
|
||||
text-align: right;
|
||||
color: $gl-text-color-secondary;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Include this in your controller and call `limit_pages` in order
|
||||
# to configure the limiter.
|
||||
#
|
||||
# Examples:
|
||||
# class MyController < ApplicationController
|
||||
# include PageLimiter
|
||||
#
|
||||
# before_action only: [:index] do
|
||||
# limit_pages(500)
|
||||
# end
|
||||
#
|
||||
# # You can override the default response
|
||||
# rescue_from PageOutOfBoundsError, with: :page_out_of_bounds
|
||||
#
|
||||
# def page_out_of_bounds(error)
|
||||
# # Page limit number is available as error.message
|
||||
# head :ok
|
||||
# end
|
||||
#
|
||||
|
||||
module PageLimiter
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
PageLimiterError = Class.new(StandardError)
|
||||
PageLimitNotANumberError = Class.new(PageLimiterError)
|
||||
PageLimitNotSensibleError = Class.new(PageLimiterError)
|
||||
PageOutOfBoundsError = Class.new(PageLimiterError)
|
||||
|
||||
included do
|
||||
rescue_from PageOutOfBoundsError, with: :default_page_out_of_bounds_response
|
||||
end
|
||||
|
||||
def limit_pages(max_page_number)
|
||||
check_page_number!(max_page_number)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# If the page exceeds the defined maximum, raise a PageOutOfBoundsError
|
||||
# If the page doesn't exceed the limit, it does nothing.
|
||||
def check_page_number!(max_page_number)
|
||||
raise PageLimitNotANumberError unless max_page_number.is_a?(Integer)
|
||||
raise PageLimitNotSensibleError unless max_page_number > 0
|
||||
|
||||
if params[:page].present? && params[:page].to_i > max_page_number
|
||||
record_page_limit_interception
|
||||
raise PageOutOfBoundsError.new(max_page_number)
|
||||
end
|
||||
end
|
||||
|
||||
# By default just return a HTTP status code and an empty response
|
||||
def default_page_out_of_bounds_response
|
||||
head :bad_request
|
||||
end
|
||||
|
||||
# Record the page limit being hit in Prometheus
|
||||
def record_page_limit_interception
|
||||
dd = DeviceDetector.new(request.user_agent)
|
||||
|
||||
Gitlab::Metrics.counter(:gitlab_page_out_of_bounds,
|
||||
controller: params[:controller],
|
||||
action: params[:action],
|
||||
bot: dd.bot?
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Explore::ProjectsController < Explore::ApplicationController
|
||||
include PageLimiter
|
||||
include ParamsBackwardCompatibility
|
||||
include RendersMemberAccess
|
||||
include SortingHelper
|
||||
|
@ -9,6 +10,13 @@ class Explore::ProjectsController < Explore::ApplicationController
|
|||
before_action :set_non_archived_param
|
||||
before_action :set_sorting
|
||||
|
||||
# Limit taken from https://gitlab.com/gitlab-org/gitlab/issues/38357
|
||||
before_action only: [:index, :trending, :starred] do
|
||||
limit_pages(200)
|
||||
end
|
||||
|
||||
rescue_from PageOutOfBoundsError, with: :page_out_of_bounds
|
||||
|
||||
def index
|
||||
@projects = load_projects
|
||||
|
||||
|
@ -53,10 +61,14 @@ class Explore::ProjectsController < Explore::ApplicationController
|
|||
|
||||
private
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def load_projects
|
||||
def load_project_counts
|
||||
@total_user_projects_count = ProjectsFinder.new(params: { non_public: true }, current_user: current_user).execute
|
||||
@total_starred_projects_count = ProjectsFinder.new(params: { starred: true }, current_user: current_user).execute
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def load_projects
|
||||
load_project_counts
|
||||
|
||||
projects = ProjectsFinder.new(current_user: current_user, params: params)
|
||||
.execute
|
||||
|
@ -80,4 +92,21 @@ class Explore::ProjectsController < Explore::ApplicationController
|
|||
def sorting_field
|
||||
Project::SORTING_PREFERENCE_FIELD
|
||||
end
|
||||
|
||||
def page_out_of_bounds(error)
|
||||
load_project_counts
|
||||
@max_page_number = error.message
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
render "page_out_of_bounds", status: :bad_request
|
||||
end
|
||||
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("explore/projects/page_out_of_bounds")
|
||||
}, status: :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,17 +15,17 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
before_action :check_snippets_available!
|
||||
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
|
||||
|
||||
# Allow read any snippet
|
||||
before_action :authorize_read_project_snippet!, except: [:new, :create, :index]
|
||||
# Allow create snippet
|
||||
before_action :authorize_create_snippet!, only: [:new, :create]
|
||||
|
||||
# Allow write(create) snippet
|
||||
before_action :authorize_create_project_snippet!, only: [:new, :create]
|
||||
# Allow read any snippet
|
||||
before_action :authorize_read_snippet!, except: [:new, :create, :index]
|
||||
|
||||
# Allow modify snippet
|
||||
before_action :authorize_update_project_snippet!, only: [:edit, :update]
|
||||
before_action :authorize_update_snippet!, only: [:edit, :update]
|
||||
|
||||
# Allow destroy snippet
|
||||
before_action :authorize_admin_project_snippet!, only: [:destroy]
|
||||
before_action :authorize_admin_snippet!, only: [:destroy]
|
||||
|
||||
respond_to :html
|
||||
|
||||
|
@ -115,16 +115,16 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
project_snippet_path(@project, @snippet)
|
||||
end
|
||||
|
||||
def authorize_read_project_snippet!
|
||||
return render_404 unless can?(current_user, :read_project_snippet, @snippet)
|
||||
def authorize_read_snippet!
|
||||
return render_404 unless can?(current_user, :read_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_update_project_snippet!
|
||||
return render_404 unless can?(current_user, :update_project_snippet, @snippet)
|
||||
def authorize_update_snippet!
|
||||
return render_404 unless can?(current_user, :update_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_admin_project_snippet!
|
||||
return render_404 unless can?(current_user, :admin_project_snippet, @snippet)
|
||||
def authorize_admin_snippet!
|
||||
return render_404 unless can?(current_user, :admin_snippet, @snippet)
|
||||
end
|
||||
|
||||
def snippet_params
|
||||
|
|
|
@ -33,7 +33,7 @@ class Snippets::NotesController < ApplicationController
|
|||
end
|
||||
|
||||
def authorize_read_snippet!
|
||||
return render_404 unless can?(current_user, :read_personal_snippet, snippet)
|
||||
return render_404 unless can?(current_user, :read_snippet, snippet)
|
||||
end
|
||||
|
||||
def authorize_create_note!
|
||||
|
|
|
@ -126,7 +126,7 @@ class SnippetsController < ApplicationController
|
|||
end
|
||||
|
||||
def authorize_read_snippet!
|
||||
return if can?(current_user, :read_personal_snippet, @snippet)
|
||||
return if can?(current_user, :read_snippet, @snippet)
|
||||
|
||||
if current_user
|
||||
render_404
|
||||
|
@ -136,15 +136,15 @@ class SnippetsController < ApplicationController
|
|||
end
|
||||
|
||||
def authorize_update_snippet!
|
||||
return render_404 unless can?(current_user, :update_personal_snippet, @snippet)
|
||||
return render_404 unless can?(current_user, :update_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_admin_snippet!
|
||||
return render_404 unless can?(current_user, :admin_personal_snippet, @snippet)
|
||||
return render_404 unless can?(current_user, :admin_snippet, @snippet)
|
||||
end
|
||||
|
||||
def authorize_create_snippet!
|
||||
return render_404 unless can?(current_user, :create_personal_snippet)
|
||||
return render_404 unless can?(current_user, :create_snippet)
|
||||
end
|
||||
|
||||
def snippet_params
|
||||
|
|
|
@ -41,6 +41,8 @@ class UploadsController < ApplicationController
|
|||
case model
|
||||
when Note
|
||||
can?(current_user, :read_project, model.project)
|
||||
when Snippet, ProjectSnippet
|
||||
can?(current_user, :read_snippet, model)
|
||||
when User
|
||||
# We validate the current user has enough (writing)
|
||||
# access to itself when a secret is given.
|
||||
|
|
|
@ -67,11 +67,11 @@ module Mutations
|
|||
end
|
||||
|
||||
def authorized_resource?(project)
|
||||
Ability.allowed?(context[:current_user], :create_project_snippet, project)
|
||||
Ability.allowed?(context[:current_user], :create_snippet, project)
|
||||
end
|
||||
|
||||
def can_create_personal_snippet?
|
||||
Ability.allowed?(context[:current_user], :create_personal_snippet)
|
||||
Ability.allowed?(context[:current_user], :create_snippet)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ module Types
|
|||
permission_field :create_snippet
|
||||
|
||||
def create_snippet
|
||||
Ability.allowed?(context[:current_user], :create_project_snippet, object)
|
||||
Ability.allowed?(context[:current_user], :create_snippet, object)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ module Types
|
|||
permission_field :create_snippet
|
||||
|
||||
def create_snippet
|
||||
Ability.allowed?(context[:current_user], :create_personal_snippet)
|
||||
Ability.allowed?(context[:current_user], :create_snippet)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,13 +76,14 @@ module MarkupHelper
|
|||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||
# the tag contents are truncated without removing the closing tag.
|
||||
def first_line_in_markdown(object, attribute, max_chars = nil, options = {})
|
||||
md = markdown_field(object, attribute, options)
|
||||
md = markdown_field(object, attribute, options.merge(post_process: false))
|
||||
return unless md.present?
|
||||
|
||||
tags = %w(a gl-emoji b pre code p span)
|
||||
tags << 'img' if options[:allow_images]
|
||||
|
||||
text = truncate_visible(md, max_chars || md.length)
|
||||
text = prepare_for_rendering(text, markdown_field_render_context(object, attribute, options))
|
||||
text = sanitize(
|
||||
text,
|
||||
tags: tags,
|
||||
|
@ -107,15 +108,12 @@ module MarkupHelper
|
|||
|
||||
def markdown_field(object, field, context = {})
|
||||
object = object.for_display if object.respond_to?(:for_display)
|
||||
redacted_field_html = object.try(:"redacted_#{field}_html")
|
||||
|
||||
return '' unless object.present?
|
||||
|
||||
redacted_field_html = object.try(:"redacted_#{field}_html")
|
||||
return redacted_field_html if redacted_field_html
|
||||
|
||||
html = Banzai.render_field(object, field, context)
|
||||
context.reverse_merge!(object.banzai_render_context(field)) if object.respond_to?(:banzai_render_context)
|
||||
|
||||
prepare_for_rendering(html, context)
|
||||
render_markdown_field(object, field, context)
|
||||
end
|
||||
|
||||
def markup(file_name, text, context = {})
|
||||
|
@ -277,6 +275,23 @@ module MarkupHelper
|
|||
Gitlab::OtherMarkup.render(file_name, text, context)
|
||||
end
|
||||
|
||||
def render_markdown_field(object, field, context = {})
|
||||
post_process = context.delete(:post_process)
|
||||
post_process = true if post_process.nil?
|
||||
|
||||
html = Banzai.render_field(object, field, context)
|
||||
|
||||
return html unless post_process
|
||||
|
||||
prepare_for_rendering(html, markdown_field_render_context(object, field, context))
|
||||
end
|
||||
|
||||
def markdown_field_render_context(object, field, base_context = {})
|
||||
return base_context unless object.respond_to?(:banzai_render_context)
|
||||
|
||||
base_context.reverse_merge(object.banzai_render_context(field))
|
||||
end
|
||||
|
||||
def prepare_for_rendering(html, context = {})
|
||||
return '' unless html.present?
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ module ProjectsHelper
|
|||
{
|
||||
environments: :read_environment,
|
||||
milestones: :read_milestone,
|
||||
snippets: :read_project_snippet,
|
||||
snippets: :read_snippet,
|
||||
settings: :admin_project,
|
||||
builds: :read_build,
|
||||
clusters: :read_cluster,
|
||||
|
@ -443,7 +443,7 @@ module ProjectsHelper
|
|||
blobs: :download_code,
|
||||
commits: :download_code,
|
||||
merge_requests: :read_merge_request,
|
||||
notes: [:read_merge_request, :download_code, :read_issue, :read_project_snippet],
|
||||
notes: [:read_merge_request, :download_code, :read_issue, :read_snippet],
|
||||
members: :read_project_member
|
||||
)
|
||||
end
|
||||
|
|
|
@ -26,19 +26,17 @@ module Emails
|
|||
mail_answer_note_thread(@merge_request, @note, note_thread_options(recipient_id, reason))
|
||||
end
|
||||
|
||||
def note_project_snippet_email(recipient_id, note_id, reason = nil)
|
||||
def note_snippet_email(recipient_id, note_id, reason = nil)
|
||||
setup_note_mail(note_id, recipient_id)
|
||||
|
||||
@snippet = @note.noteable
|
||||
@target_url = project_snippet_url(*note_target_url_options)
|
||||
mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id, reason))
|
||||
end
|
||||
|
||||
def note_personal_snippet_email(recipient_id, note_id, reason = nil)
|
||||
setup_note_mail(note_id, recipient_id)
|
||||
case @snippet
|
||||
when ProjectSnippet
|
||||
@target_url = project_snippet_url(*note_target_url_options)
|
||||
when Snippet
|
||||
@target_url = gitlab_snippet_url(@note.noteable)
|
||||
end
|
||||
|
||||
@snippet = @note.noteable
|
||||
@target_url = gitlab_snippet_url(@note.noteable)
|
||||
mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id, reason))
|
||||
end
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class Ability
|
|||
# read the given snippet.
|
||||
def users_that_can_read_personal_snippet(users, snippet)
|
||||
DeclarativePolicy.subject_scope do
|
||||
users.select { |u| allowed?(u, :read_personal_snippet, snippet) }
|
||||
users.select { |u| allowed?(u, :read_snippet, snippet) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -62,6 +62,10 @@ module ProjectFeaturesCompatibility
|
|||
write_feature_attribute_string(:snippets_access_level, value)
|
||||
end
|
||||
|
||||
def pages_access_level=(value)
|
||||
write_feature_attribute_string(:pages_access_level, value)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def write_feature_attribute_boolean(field, value)
|
||||
|
|
|
@ -145,10 +145,8 @@ class Event < ApplicationRecord
|
|||
Ability.allowed?(user, :read_issue, note? ? note_target : target)
|
||||
elsif merge_request? || merge_request_note?
|
||||
Ability.allowed?(user, :read_merge_request, note? ? note_target : target)
|
||||
elsif personal_snippet_note?
|
||||
Ability.allowed?(user, :read_personal_snippet, note_target)
|
||||
elsif project_snippet_note?
|
||||
Ability.allowed?(user, :read_project_snippet, note_target)
|
||||
elsif personal_snippet_note? || project_snippet_note?
|
||||
Ability.allowed?(user, :read_snippet, note_target)
|
||||
elsif milestone?
|
||||
Ability.allowed?(user, :read_milestone, project)
|
||||
else
|
||||
|
|
|
@ -367,7 +367,7 @@ class Note < ApplicationRecord
|
|||
end
|
||||
|
||||
def noteable_ability_name
|
||||
for_snippet? ? noteable.class.name.underscore : noteable_type.demodulize.underscore
|
||||
for_snippet? ? 'snippet' : noteable_type.demodulize.underscore
|
||||
end
|
||||
|
||||
def can_be_discussion_note?
|
||||
|
|
|
@ -322,7 +322,7 @@ class Project < ApplicationRecord
|
|||
:pages_enabled?, :public_pages?, :private_pages?,
|
||||
:merge_requests_access_level, :forking_access_level, :issues_access_level,
|
||||
:wiki_access_level, :snippets_access_level, :builds_access_level,
|
||||
:repository_access_level,
|
||||
:repository_access_level, :pages_access_level,
|
||||
to: :project_feature, allow_nil: true
|
||||
delegate :scheduled?, :started?, :in_progress?, :failed?, :finished?,
|
||||
prefix: :import, to: :import_state, allow_nil: true
|
||||
|
@ -2274,7 +2274,7 @@ class Project < ApplicationRecord
|
|||
end
|
||||
|
||||
def snippets_visible?(user = nil)
|
||||
Ability.allowed?(user, :read_project_snippet, self)
|
||||
Ability.allowed?(user, :read_snippet, self)
|
||||
end
|
||||
|
||||
def max_attachment_size
|
||||
|
|
|
@ -215,9 +215,7 @@ class Snippet < ApplicationRecord
|
|||
end
|
||||
|
||||
def embeddable?
|
||||
ability = project_id? ? :read_project_snippet : :read_personal_snippet
|
||||
|
||||
Ability.allowed?(nil, ability, self)
|
||||
Ability.allowed?(nil, :read_snippet, self)
|
||||
end
|
||||
|
||||
def notes_with_associations
|
||||
|
@ -240,7 +238,7 @@ class Snippet < ApplicationRecord
|
|||
end
|
||||
|
||||
def to_ability_name
|
||||
model_name.singular
|
||||
'snippet'
|
||||
end
|
||||
|
||||
def valid_secret_token?(token)
|
||||
|
|
|
@ -75,7 +75,7 @@ class GlobalPolicy < BasePolicy
|
|||
|
||||
rule { ~anonymous }.policy do
|
||||
enable :read_instance_metadata
|
||||
enable :create_personal_snippet
|
||||
enable :create_snippet
|
||||
end
|
||||
|
||||
rule { admin }.policy do
|
||||
|
@ -83,7 +83,7 @@ class GlobalPolicy < BasePolicy
|
|||
enable :update_custom_attribute
|
||||
end
|
||||
|
||||
rule { external_user }.prevent :create_personal_snippet
|
||||
rule { external_user }.prevent :create_snippet
|
||||
end
|
||||
|
||||
GlobalPolicy.prepend_if_ee('EE::GlobalPolicy')
|
||||
|
|
|
@ -6,19 +6,19 @@ class PersonalSnippetPolicy < BasePolicy
|
|||
condition(:internal_snippet, scope: :subject) { @subject.internal? }
|
||||
|
||||
rule { public_snippet }.policy do
|
||||
enable :read_personal_snippet
|
||||
enable :read_snippet
|
||||
enable :create_note
|
||||
end
|
||||
|
||||
rule { is_author | admin }.policy do
|
||||
enable :read_personal_snippet
|
||||
enable :update_personal_snippet
|
||||
enable :admin_personal_snippet
|
||||
enable :read_snippet
|
||||
enable :update_snippet
|
||||
enable :admin_snippet
|
||||
enable :create_note
|
||||
end
|
||||
|
||||
rule { internal_snippet & ~external_user }.policy do
|
||||
enable :read_personal_snippet
|
||||
enable :read_snippet
|
||||
enable :create_note
|
||||
end
|
||||
|
||||
|
@ -26,8 +26,5 @@ class PersonalSnippetPolicy < BasePolicy
|
|||
|
||||
rule { can?(:create_note) }.enable :award_emoji
|
||||
|
||||
rule { can?(:read_all_resources) }.enable :read_personal_snippet
|
||||
|
||||
# Aliasing the ability to ease GraphQL permissions check
|
||||
rule { can?(:read_personal_snippet) }.enable :read_snippet
|
||||
rule { can?(:read_all_resources) }.enable :read_snippet
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class ProjectPolicy < BasePolicy
|
|||
merge_request
|
||||
label
|
||||
milestone
|
||||
project_snippet
|
||||
snippet
|
||||
wiki
|
||||
note
|
||||
pipeline
|
||||
|
@ -185,7 +185,7 @@ class ProjectPolicy < BasePolicy
|
|||
enable :read_issue
|
||||
enable :read_label
|
||||
enable :read_milestone
|
||||
enable :read_project_snippet
|
||||
enable :read_snippet
|
||||
enable :read_project_member
|
||||
enable :read_note
|
||||
enable :create_project
|
||||
|
@ -208,7 +208,7 @@ class ProjectPolicy < BasePolicy
|
|||
enable :download_code
|
||||
enable :read_statistics
|
||||
enable :download_wiki_code
|
||||
enable :create_project_snippet
|
||||
enable :create_snippet
|
||||
enable :update_issue
|
||||
enable :reopen_issue
|
||||
enable :admin_issue
|
||||
|
@ -286,8 +286,8 @@ class ProjectPolicy < BasePolicy
|
|||
rule { can?(:maintainer_access) }.policy do
|
||||
enable :admin_board
|
||||
enable :push_to_delete_protected_branch
|
||||
enable :update_project_snippet
|
||||
enable :admin_project_snippet
|
||||
enable :update_snippet
|
||||
enable :admin_snippet
|
||||
enable :admin_project_member
|
||||
enable :admin_note
|
||||
enable :admin_wiki
|
||||
|
@ -352,7 +352,7 @@ class ProjectPolicy < BasePolicy
|
|||
end
|
||||
|
||||
rule { snippets_disabled }.policy do
|
||||
prevent(*create_read_update_admin_destroy(:project_snippet))
|
||||
prevent(*create_read_update_admin_destroy(:snippet))
|
||||
end
|
||||
|
||||
rule { wiki_disabled }.policy do
|
||||
|
@ -405,7 +405,7 @@ class ProjectPolicy < BasePolicy
|
|||
enable :read_wiki
|
||||
enable :read_label
|
||||
enable :read_milestone
|
||||
enable :read_project_snippet
|
||||
enable :read_snippet
|
||||
enable :read_project_member
|
||||
enable :read_merge_request
|
||||
enable :read_note
|
||||
|
|
|
@ -14,44 +14,41 @@ class ProjectSnippetPolicy < BasePolicy
|
|||
# We have to check both project feature visibility and a snippet visibility and take the stricter one
|
||||
# This will be simplified - check https://gitlab.com/gitlab-org/gitlab-foss/issues/27573
|
||||
rule { ~can?(:read_project) }.policy do
|
||||
prevent :read_project_snippet
|
||||
prevent :update_project_snippet
|
||||
prevent :admin_project_snippet
|
||||
prevent :read_snippet
|
||||
prevent :update_snippet
|
||||
prevent :admin_snippet
|
||||
end
|
||||
|
||||
# we have to use this complicated prevent because the delegated project policy
|
||||
# is overly greedy in allowing :read_project_snippet, since it doesn't have any
|
||||
# information about the snippet. However, :read_project_snippet on the *project*
|
||||
# is used to hide/show various snippet-related controls, so we can't just move
|
||||
# all of the handling here.
|
||||
# we have to use this complicated prevent because the delegated project
|
||||
# policy is overly greedy in allowing :read_snippet, since it doesn't have
|
||||
# any information about the snippet. However, :read_snippet on the *project*
|
||||
# is used to hide/show various snippet-related controls, so we can't just
|
||||
# move all of the handling here.
|
||||
rule do
|
||||
all?(private_snippet | (internal_snippet & external_user),
|
||||
~project.guest,
|
||||
~is_author,
|
||||
~can?(:read_all_resources))
|
||||
end.prevent :read_project_snippet
|
||||
end.prevent :read_snippet
|
||||
|
||||
rule { internal_snippet & ~is_author & ~admin }.policy do
|
||||
prevent :update_project_snippet
|
||||
prevent :admin_project_snippet
|
||||
prevent :update_snippet
|
||||
prevent :admin_snippet
|
||||
end
|
||||
|
||||
rule { public_snippet }.enable :read_project_snippet
|
||||
rule { public_snippet }.enable :read_snippet
|
||||
|
||||
rule { is_author & ~project.reporter & ~admin }.policy do
|
||||
prevent :admin_project_snippet
|
||||
prevent :admin_snippet
|
||||
end
|
||||
|
||||
rule { is_author | admin }.policy do
|
||||
enable :read_project_snippet
|
||||
enable :update_project_snippet
|
||||
enable :admin_project_snippet
|
||||
enable :read_snippet
|
||||
enable :update_snippet
|
||||
enable :admin_snippet
|
||||
end
|
||||
|
||||
rule { ~can?(:read_project_snippet) }.prevent :create_note
|
||||
|
||||
# Aliasing the ability to ease GraphQL permissions check
|
||||
rule { can?(:read_project_snippet) }.enable :read_snippet
|
||||
rule { ~can?(:read_snippet) }.prevent :create_note
|
||||
end
|
||||
|
||||
ProjectSnippetPolicy.prepend_if_ee('EE::ProjectSnippetPolicy')
|
||||
|
|
|
@ -36,9 +36,7 @@ module Snippets
|
|||
attr_reader :snippet
|
||||
|
||||
def user_can_delete_snippet?
|
||||
return can?(current_user, :admin_project_snippet, snippet) if project
|
||||
|
||||
can?(current_user, :admin_personal_snippet, snippet)
|
||||
can?(current_user, :admin_snippet, snippet)
|
||||
end
|
||||
|
||||
def service_response_error(message, http_status)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
.form-group
|
||||
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
|
||||
= f.number_field :session_expire_delay, class: 'form-control'
|
||||
%span.form-text.text-muted#session_expire_delay_help_block= _('GitLab restart is required to apply changes')
|
||||
%span.form-text.text-muted#session_expire_delay_help_block= _('GitLab restart is required to apply changes.')
|
||||
|
||||
= render_if_exists 'admin/application_settings/personal_access_token_expiration_policy', form: f
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
- if current_user && current_user.snippets.any? || @snippets.any?
|
||||
.page-title-controls
|
||||
- if can?(current_user, :create_personal_snippet)
|
||||
- if can?(current_user, :create_snippet)
|
||||
= link_to _("New snippet"), new_snippet_path, class: "btn btn-success", title: _("New snippet")
|
||||
|
||||
.top-area
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- @hide_top_links = true
|
||||
- page_title "Snippets"
|
||||
- header_title "Snippets", dashboard_snippets_path
|
||||
- button_path = new_snippet_path if can?(current_user, :create_personal_snippet)
|
||||
- button_path = new_snippet_path if can?(current_user, :create_snippet)
|
||||
|
||||
= render 'dashboard/snippets_head'
|
||||
- if current_user.snippets.exists?
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
- @hide_top_links = true
|
||||
- page_title _("Projects")
|
||||
- header_title _("Projects"), dashboard_projects_path
|
||||
|
||||
= render_dashboard_gold_trial(current_user)
|
||||
|
||||
- if current_user
|
||||
= render 'dashboard/projects_head', project_tab_filter: :explore
|
||||
- else
|
||||
= render 'explore/head'
|
||||
|
||||
= render 'explore/projects/nav' unless Feature.enabled?(:project_list_filter_bar) && current_user
|
||||
|
||||
.nothing-here-block
|
||||
.svg-content
|
||||
= image_tag 'illustrations/profile-page/personal-project.svg', size: '75'
|
||||
.text-content
|
||||
%h5= _("Maximum page reached")
|
||||
%p= _("Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further.")
|
||||
|
||||
= link_to _("Back to page %{number}") % { number: @max_page_number }, request.params.merge(page: @max_page_number), class: 'btn btn-inverted'
|
|
@ -21,7 +21,7 @@
|
|||
- if @project&.persisted?
|
||||
- create_project_issue = show_new_issue_link?(@project)
|
||||
- merge_project = merge_request_source_project_for_project(@project)
|
||||
- create_project_snippet = can?(current_user, :create_project_snippet, @project)
|
||||
- create_project_snippet = can?(current_user, :create_snippet, @project)
|
||||
|
||||
- if create_project_issue || merge_project || create_project_snippet
|
||||
%li.dropdown-bold-header
|
||||
|
@ -38,5 +38,5 @@
|
|||
%li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
|
||||
- if current_user.can_create_group?
|
||||
%li= link_to _('New group'), new_group_path
|
||||
- if current_user.can?(:create_personal_snippet)
|
||||
- if current_user.can?(:create_snippet)
|
||||
%li= link_to _('New snippet'), new_snippet_path, class: 'qa-global-new-snippet-link'
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
= render 'note_email'
|
|
@ -1 +0,0 @@
|
|||
<%= render 'note_email' %>
|
|
@ -1,5 +1,5 @@
|
|||
- can_create_issue = show_new_issue_link?(@project)
|
||||
- can_create_project_snippet = can?(current_user, :create_project_snippet, @project)
|
||||
- can_create_project_snippet = can?(current_user, :create_snippet, @project)
|
||||
- can_push_code = can?(current_user, :push_code, @project)
|
||||
- create_mr_from_new_fork = can?(current_user, :fork_project, @project) && can?(current_user, :create_merge_request_in, @project)
|
||||
- merge_project = merge_request_source_project_for_project(@project)
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
- return unless current_user
|
||||
|
||||
.d-none.d-sm-block
|
||||
- if can?(current_user, :update_project_snippet, @snippet)
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
= link_to edit_project_snippet_path(@project, @snippet), class: "btn btn-grouped" do
|
||||
= _('Edit')
|
||||
- if can?(current_user, :admin_project_snippet, @snippet)
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
= link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
|
||||
= _('Delete')
|
||||
- if can?(current_user, :create_project_snippet, @project)
|
||||
- if can?(current_user, :create_snippet, @project)
|
||||
= link_to new_project_snippet_path(@project), class: 'btn btn-grouped btn-inverted btn-success', title: _("New snippet") do
|
||||
= _('New snippet')
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
= link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
|
||||
- if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet)
|
||||
- if can?(current_user, :create_snippet, @project) || can?(current_user, :update_snippet, @snippet)
|
||||
.d-block.d-sm-none.dropdown
|
||||
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
|
||||
= _('Options')
|
||||
= icon('caret-down')
|
||||
.dropdown-menu.dropdown-menu-full-width
|
||||
%ul
|
||||
- if can?(current_user, :create_project_snippet, @project)
|
||||
- if can?(current_user, :create_snippet, @project)
|
||||
%li
|
||||
= link_to new_project_snippet_path(@project), title: _("New snippet") do
|
||||
= _('New snippet')
|
||||
- if can?(current_user, :admin_project_snippet, @snippet)
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
%li
|
||||
= link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
|
||||
= _('Delete')
|
||||
- if can?(current_user, :update_project_snippet, @snippet)
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
%li
|
||||
= link_to edit_project_snippet_path(@project, @snippet) do
|
||||
= _('Edit')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
- include_private = @project.team.member?(current_user) || current_user.admin?
|
||||
= render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private }
|
||||
|
||||
- if can?(current_user, :create_project_snippet, @project)
|
||||
- if can?(current_user, :create_snippet, @project)
|
||||
.nav-controls
|
||||
= link_to _("New snippet"), new_project_snippet_path(@project), class: "btn btn-success", title: _("New snippet")
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
- return unless current_user
|
||||
|
||||
.d-none.d-sm-block
|
||||
- if can?(current_user, :update_personal_snippet, @snippet)
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped" do
|
||||
= _("Edit")
|
||||
- if can?(current_user, :admin_personal_snippet, @snippet)
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
= link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
|
||||
= _("Delete")
|
||||
- if can?(current_user, :create_personal_snippet)
|
||||
- if can?(current_user, :create_snippet)
|
||||
= link_to new_snippet_path, class: "btn btn-grouped btn-success btn-inverted", title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if @snippet.submittable_as_spam_by?(current_user)
|
||||
|
@ -18,15 +18,15 @@
|
|||
= icon('caret-down')
|
||||
.dropdown-menu.dropdown-menu-full-width
|
||||
%ul
|
||||
- if can?(current_user, :create_personal_snippet)
|
||||
- if can?(current_user, :create_snippet)
|
||||
%li
|
||||
= link_to new_snippet_path, title: _("New snippet") do
|
||||
= _("New snippet")
|
||||
- if can?(current_user, :admin_personal_snippet, @snippet)
|
||||
- if can?(current_user, :admin_snippet, @snippet)
|
||||
%li
|
||||
= link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
|
||||
= _("Delete")
|
||||
- if can?(current_user, :update_personal_snippet, @snippet)
|
||||
- if can?(current_user, :update_snippet, @snippet)
|
||||
%li
|
||||
= link_to edit_snippet_path(@snippet) do
|
||||
= _("Edit")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
- current_user_empty_message_header = s_('UserProfile|You haven\'t created any snippets.')
|
||||
- current_user_empty_message_description = s_('UserProfile|Snippets in GitLab can either be private, internal, or public.')
|
||||
- primary_button_label = _('New snippet')
|
||||
- primary_button_link = new_snippet_path if can?(current_user, :create_personal_snippet)
|
||||
- primary_button_link = new_snippet_path if can?(current_user, :create_snippet)
|
||||
- visitor_empty_message = s_('UserProfile|No snippets found.')
|
||||
|
||||
.snippets-list-holder
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reducing whitespace in group list to show more on screen and reduce vertical scrolling
|
||||
merge_request: 21584
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Limit page number on explore/projects
|
||||
merge_request: 22876
|
||||
author:
|
||||
type: performance
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Prevent unnecessary Gitaly calls when rendering comment excerpts in todos and
|
||||
activity feed
|
||||
merge_request: 23100
|
||||
author:
|
||||
type: performance
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Stop NoMethodError happening for 1.16+ Kubernetes clusters
|
||||
merge_request: 23149
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add pages_access_level to projects API
|
||||
merge_request: 23176
|
||||
author: Mathieu Parent
|
||||
type: added
|
|
@ -1008,6 +1008,7 @@ POST /projects
|
|||
| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `pages_access_level` | string | no | One of `disabled`, `private`, `enabled` or `public` |
|
||||
| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
|
||||
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
|
||||
| `container_expiration_policy_attributes` | hash | no | Update the container expiration policy for this project. Accepts: `cadence` (string), `keep_n` (string), `older_than` (string), `name_regex` (string), `enabled` (boolean) |
|
||||
|
@ -1074,6 +1075,7 @@ POST /projects/user/:user_id
|
|||
| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `pages_access_level` | string | no | One of `disabled`, `private`, `enabled` or `public` |
|
||||
| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
|
||||
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
|
||||
| `shared_runners_enabled` | boolean | no | Enable shared runners for this project |
|
||||
|
@ -1139,6 +1141,7 @@ PUT /projects/:id
|
|||
| `builds_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `wiki_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `snippets_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `pages_access_level` | string | no | One of `disabled`, `private`, `enabled` or `public` |
|
||||
| `resolve_outdated_diff_discussions` | boolean | no | Automatically resolve merge request diffs discussions on lines changed with a push |
|
||||
| `container_registry_enabled` | boolean | no | Enable container registry for this project |
|
||||
| `container_expiration_policy_attributes` | hash | no | Update the container expiration policy for this project. Accepts: `cadence` (string), `keep_n` (string), `older_than` (string), `name_regex` (string), `enabled` (boolean) |
|
||||
|
|
|
@ -167,8 +167,15 @@ end
|
|||
Normally, GitLab CE/EE tests use a local clone of Gitaly in
|
||||
`tmp/tests/gitaly` pinned at the version specified in
|
||||
`GITALY_SERVER_VERSION`. The `GITALY_SERVER_VERSION` file supports also
|
||||
branches and SHA to use a custom commit in <https://gitlab.com/gitlab-org/gitaly>. If
|
||||
you want to run tests locally against a modified version of Gitaly you
|
||||
branches and SHA to use a custom commit in <https://gitlab.com/gitlab-org/gitaly>.
|
||||
|
||||
NOTE: **Note:**
|
||||
With the introduction of auto-deploy for Gitaly, the format of
|
||||
`GITALY_SERVER_VERSION` was aligned with Omnibus syntax.
|
||||
It no longer supports `=revision`, it will evaluate the file content as a Git
|
||||
reference (branch or SHA), only if it matches a semver it will prepend a `v`.
|
||||
|
||||
If you want to run tests locally against a modified version of Gitaly you
|
||||
can replace `tmp/tests/gitaly` with a symlink. This is much faster
|
||||
because if will avoid a Gitaly re-install each time you run `rspec`.
|
||||
|
||||
|
@ -185,8 +192,7 @@ to manually run `make` again.
|
|||
|
||||
Note that CI tests will not use your locally modified version of
|
||||
Gitaly. To use a custom Gitaly version in CI you need to update
|
||||
GITALY_SERVER_VERSION. You can use the format `=revision` to use a
|
||||
non-tagged commit from <https://gitlab.com/gitlab-org/gitaly> in CI.
|
||||
GITALY_SERVER_VERSION as described at the beginning of this paragraph.
|
||||
|
||||
To use a different Gitaly repository, e.g., if your changes are present
|
||||
on a fork, you can specify a `GITALY_REPO_URL` environment variable when
|
||||
|
|
|
@ -157,7 +157,7 @@ The plain text title and description of the issue fill the top center of the iss
|
|||
The description fully supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm),
|
||||
allowing many formatting options.
|
||||
|
||||
> [Since GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/issues/10103), changes to an issue's description are listed in the [issue history](#23-issue-history).**(STARTER)**
|
||||
> [Since GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/issues/10103), changes to an issue's description are listed in the [issue history](#23-issue-history).**(STARTER)**
|
||||
|
||||
#### 17. Mentions
|
||||
|
||||
|
|
|
@ -127,6 +127,8 @@ module API
|
|||
case awardable
|
||||
when Note
|
||||
read_ability(awardable.noteable)
|
||||
when Snippet, ProjectSnippet
|
||||
:read_snippet
|
||||
else
|
||||
:"read_#{awardable.class.to_s.underscore}"
|
||||
end
|
||||
|
|
|
@ -311,6 +311,7 @@ module API
|
|||
expose(:wiki_access_level) { |project, options| project.project_feature.string_access_level(:wiki) }
|
||||
expose(:builds_access_level) { |project, options| project.project_feature.string_access_level(:builds) }
|
||||
expose(:snippets_access_level) { |project, options| project.project_feature.string_access_level(:snippets) }
|
||||
expose(:pages_access_level) { |project, options| project.project_feature.string_access_level(:pages) }
|
||||
|
||||
expose :shared_runners_enabled
|
||||
expose :lfs_enabled?, as: :lfs_enabled
|
||||
|
|
|
@ -72,7 +72,15 @@ module API
|
|||
end
|
||||
|
||||
def noteable_read_ability_name(noteable)
|
||||
"read_#{noteable.class.to_s.underscore}".to_sym
|
||||
"read_#{ability_name(noteable)}".to_sym
|
||||
end
|
||||
|
||||
def ability_name(noteable)
|
||||
if noteable.respond_to?(:to_ability_name)
|
||||
noteable.to_ability_name
|
||||
else
|
||||
noteable.class.to_s.underscore
|
||||
end
|
||||
end
|
||||
|
||||
def find_noteable(parent_type, parent_id, noteable_type, noteable_id)
|
||||
|
|
|
@ -27,6 +27,7 @@ module API
|
|||
optional :wiki_access_level, type: String, values: %w(disabled private enabled), desc: 'Wiki access level. One of `disabled`, `private` or `enabled`'
|
||||
optional :builds_access_level, type: String, values: %w(disabled private enabled), desc: 'Builds access level. One of `disabled`, `private` or `enabled`'
|
||||
optional :snippets_access_level, type: String, values: %w(disabled private enabled), desc: 'Snippets access level. One of `disabled`, `private` or `enabled`'
|
||||
optional :pages_access_level, type: String, values: %w(disabled private enabled public), desc: 'Pages access level. One of `disabled`, `private`, `enabled` or `public`'
|
||||
|
||||
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
|
||||
optional :resolve_outdated_diff_discussions, type: Boolean, desc: 'Automatically resolve merge request diffs discussions on lines changed with a push'
|
||||
|
@ -107,6 +108,7 @@ module API
|
|||
:name,
|
||||
:only_allow_merge_if_all_discussions_are_resolved,
|
||||
:only_allow_merge_if_pipeline_succeeds,
|
||||
:pages_access_level,
|
||||
:path,
|
||||
:printing_merge_request_link_enabled,
|
||||
:public_builds,
|
||||
|
|
|
@ -60,7 +60,7 @@ module API
|
|||
mutually_exclusive :code, :content
|
||||
end
|
||||
post ":id/snippets" do
|
||||
authorize! :create_project_snippet, user_project
|
||||
authorize! :create_snippet, user_project
|
||||
snippet_params = declared_params(include_missing: false).merge(request: request, api: true)
|
||||
snippet_params[:content] = snippet_params.delete(:code) if snippet_params[:code].present?
|
||||
|
||||
|
@ -97,7 +97,7 @@ module API
|
|||
snippet = snippets_for_current_user.find_by(id: params.delete(:snippet_id))
|
||||
not_found!('Snippet') unless snippet
|
||||
|
||||
authorize! :update_project_snippet, snippet
|
||||
authorize! :update_snippet, snippet
|
||||
|
||||
snippet_params = declared_params(include_missing: false)
|
||||
.merge(request: request, api: true)
|
||||
|
@ -126,7 +126,7 @@ module API
|
|||
snippet = snippets_for_current_user.find_by(id: params[:snippet_id])
|
||||
not_found!('Snippet') unless snippet
|
||||
|
||||
authorize! :admin_project_snippet, snippet
|
||||
authorize! :admin_snippet, snippet
|
||||
|
||||
destroy_conditionally!(snippet) do |snippet|
|
||||
service = ::Snippets::DestroyService.new(current_user, snippet)
|
||||
|
|
|
@ -106,7 +106,7 @@ module API
|
|||
snippet = snippets_for_current_user.find_by_id(params.delete(:id))
|
||||
break not_found!('Snippet') unless snippet
|
||||
|
||||
authorize! :update_personal_snippet, snippet
|
||||
authorize! :update_snippet, snippet
|
||||
|
||||
attrs = declared_params(include_missing: false).merge(request: request, api: true)
|
||||
service_response = ::Snippets::UpdateService.new(nil, current_user, attrs).execute(snippet)
|
||||
|
@ -132,7 +132,7 @@ module API
|
|||
snippet = snippets_for_current_user.find_by_id(params.delete(:id))
|
||||
break not_found!('Snippet') unless snippet
|
||||
|
||||
authorize! :admin_personal_snippet, snippet
|
||||
authorize! :admin_snippet, snippet
|
||||
|
||||
destroy_conditionally!(snippet) do |snippet|
|
||||
service = ::Snippets::DestroyService.new(current_user, snippet)
|
||||
|
|
|
@ -12,7 +12,7 @@ module Banzai
|
|||
private
|
||||
|
||||
def can_read_reference?(user, ref_project, node)
|
||||
can?(user, :read_project_snippet, referenced_by([node]).first)
|
||||
can?(user, :read_snippet, referenced_by([node]).first)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ module Gitlab
|
|||
|
||||
CleanupError = Class.new(StandardError)
|
||||
BG_CLEANUP_RUNTIME_S = 10
|
||||
FG_CLEANUP_RUNTIME_S = 0.5
|
||||
FG_CLEANUP_RUNTIME_S = 1
|
||||
|
||||
MUTEX = Mutex.new
|
||||
|
||||
|
@ -127,7 +127,10 @@ module Gitlab
|
|||
# error.
|
||||
# Failing to remove the tmp directory could leave the `gpg-agent` process
|
||||
# running forever.
|
||||
Retriable.retriable(max_elapsed_time: cleanup_time, base_interval: 0.1) do
|
||||
#
|
||||
# 15 tries will never complete within the maximum time with exponential
|
||||
# backoff. So our limit is the runtime, not the number of tries.
|
||||
Retriable.retriable(max_elapsed_time: cleanup_time, base_interval: 0.1, tries: 15) do
|
||||
FileUtils.remove_entry(tmp_dir) if File.exist?(tmp_dir)
|
||||
end
|
||||
rescue => e
|
||||
|
|
|
@ -16,6 +16,7 @@ module Gitlab
|
|||
SUPPORTED_API_GROUPS = {
|
||||
core: { group: 'api', version: 'v1' },
|
||||
rbac: { group: 'apis/rbac.authorization.k8s.io', version: 'v1' },
|
||||
apps: { group: 'apis/apps', version: 'v1' },
|
||||
extensions: { group: 'apis/extensions', version: 'v1beta1' },
|
||||
istio: { group: 'apis/networking.istio.io', version: 'v1alpha3' },
|
||||
knative: { group: 'apis/serving.knative.dev', version: 'v1alpha1' }
|
||||
|
@ -74,10 +75,6 @@ module Gitlab
|
|||
:update_role_binding,
|
||||
to: :rbac_client
|
||||
|
||||
# Deployments resource is currently on the apis/extensions api group
|
||||
delegate :get_deployments,
|
||||
to: :extensions_client
|
||||
|
||||
# non-entity methods that can only work with the core client
|
||||
# as it uses the pods/log resource
|
||||
delegate :get_pod_log,
|
||||
|
@ -103,6 +100,21 @@ module Gitlab
|
|||
validate_url!
|
||||
end
|
||||
|
||||
# Deployments resource is currently on the apis/extensions api group
|
||||
# until Kubernetes 1.15. Kubernetest 1.16+ has deployments resources in
|
||||
# the apis/apps api group.
|
||||
#
|
||||
# As we still support Kubernetes 1.12+, we will need to support both.
|
||||
def get_deployments(**args)
|
||||
extensions_client.discover unless extensions_client.discovered
|
||||
|
||||
if extensions_client.respond_to?(:get_deployments)
|
||||
extensions_client.get_deployments(**args)
|
||||
else
|
||||
apps_client.get_deployments(**args)
|
||||
end
|
||||
end
|
||||
|
||||
def create_or_update_cluster_role_binding(resource)
|
||||
if cluster_role_binding_exists?(resource)
|
||||
update_cluster_role_binding(resource)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
4470
locale/bg/gitlab.po
4470
locale/bg/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5086
locale/de/gitlab.po
5086
locale/de/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4470
locale/eo/gitlab.po
4470
locale/eo/gitlab.po
File diff suppressed because it is too large
Load Diff
4994
locale/es/gitlab.po
4994
locale/es/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4580
locale/fr/gitlab.po
4580
locale/fr/gitlab.po
File diff suppressed because it is too large
Load Diff
|
@ -2528,6 +2528,9 @@ msgstr ""
|
|||
msgid "Average per day: %{average}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Back to page %{number}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Background Color"
|
||||
msgstr ""
|
||||
|
||||
|
@ -8951,7 +8954,7 @@ msgstr ""
|
|||
msgid "GitLab project export"
|
||||
msgstr ""
|
||||
|
||||
msgid "GitLab restart is required to apply changes"
|
||||
msgid "GitLab restart is required to apply changes."
|
||||
msgstr ""
|
||||
|
||||
msgid "GitLab single sign on URL"
|
||||
|
@ -10922,7 +10925,7 @@ msgstr ""
|
|||
msgid "Leave Admin Mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Leave blank for no limit. Once set, existing personal access tokens may be revoked"
|
||||
msgid "Leave blank for no limit. Once set, existing personal access tokens may be revoked."
|
||||
msgstr ""
|
||||
|
||||
msgid "Leave edit mode? All unsaved changes will be lost."
|
||||
|
@ -11496,6 +11499,9 @@ msgstr ""
|
|||
msgid "Maximum number of mirrors that can be synchronizing at the same time."
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum page reached"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum push size (MB)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -17410,6 +17416,9 @@ msgstr ""
|
|||
msgid "Sorry, no projects matched your search"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further."
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry, your filter produced no results"
|
||||
msgstr ""
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4476
locale/it/gitlab.po
4476
locale/it/gitlab.po
File diff suppressed because it is too large
Load Diff
5089
locale/ja/gitlab.po
5089
locale/ja/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
5181
locale/ko/gitlab.po
5181
locale/ko/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6688
locale/ru/gitlab.po
6688
locale/ru/gitlab.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue