Commit 6a45bfc3 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 1ff62e16a625
......@@ -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;
......
# 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
# 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 @@ def starred
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 @@ def default_sort_order
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 @@ def spammable_path
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 @@ def finder_params
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 @@ def spammable_path
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 @@ def authorize_read_snippet!
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 @@ def authorize_access!
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 @@ def find_object(full_path:)
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 @@ class Project < BasePermissionType
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 @@ class User < BasePermissionType
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 @@ def link_to_html(redacted, url, html_options = {})
# +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 @@ def markdown(text, context = {})
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?
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)
redacted_field_html = object.try(:"redacted_#{field}_html")
return redacted_field_html if redacted_field_html
prepare_for_rendering(html, context)
render_markdown_field(object, field, context)
end
def markup(file_name, text, context = {})
......@@ -277,6 +275,23 @@ def other_markup_unsafe(file_name, text, context = {})
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 @@ def tab_ability_map
{
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 @@ def search_tab_ability_map
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 @@ def note_merge_request_email(recipient_id, note_id, reason = nil)
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 @@ def users_that_can_read_group(users, group)
# 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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment