Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-10 00:09:19 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-10 00:09:19 +0300
commitb5944525b015e4efb4cd2c1d09ec37566d7691a0 (patch)
tree23134355a45b69298483e6c08b65ef6b23b8bd26 /app
parent16cfd85bcf0046ae97d7ea84dae7eea3eafafe99 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/store/getters.js16
-rw-r--r--app/assets/javascripts/diffs/utils/suggestions.js28
-rw-r--r--app/assets/javascripts/notes/components/note_body.vue26
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue1
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/projects/notes_controller.rb14
-rw-r--r--app/graphql/mutations/notes/create/base.rb9
-rw-r--r--app/helpers/application_settings_helper.rb1
-rw-r--r--app/models/application_setting.rb3
-rw-r--r--app/models/application_setting_implementation.rb1
-rw-r--r--app/services/concerns/alert_management/alert_processing.rb2
-rw-r--r--app/views/admin/application_settings/_note_limits.html.haml9
-rw-r--r--app/views/admin/application_settings/network.html.haml11
-rw-r--r--app/views/doorkeeper/applications/_delete_form.html.haml2
-rw-r--r--app/views/doorkeeper/applications/index.html.haml4
15 files changed, 123 insertions, 5 deletions
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 149afc01056..1fc2a684e95 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -4,6 +4,7 @@ import {
INLINE_DIFF_VIEW_TYPE,
INLINE_DIFF_LINES_KEY,
} from '../constants';
+import { computeSuggestionCommitMessage } from '../utils/suggestions';
import { parallelizeDiffLines } from './utils';
export * from './getters_versions_dropdowns';
@@ -154,3 +155,18 @@ export const diffLines = (state) => (file, unifiedDiffComponents) => {
state.diffViewType === INLINE_DIFF_VIEW_TYPE,
);
};
+
+export function suggestionCommitMessage(state) {
+ return (values = {}) =>
+ computeSuggestionCommitMessage({
+ message: state.defaultSuggestionCommitMessage,
+ values: {
+ branch_name: state.branchName,
+ project_path: state.projectPath,
+ project_name: state.projectName,
+ username: state.username,
+ user_full_name: state.userFullName,
+ ...values,
+ },
+ });
+}
diff --git a/app/assets/javascripts/diffs/utils/suggestions.js b/app/assets/javascripts/diffs/utils/suggestions.js
new file mode 100644
index 00000000000..a272f7f3257
--- /dev/null
+++ b/app/assets/javascripts/diffs/utils/suggestions.js
@@ -0,0 +1,28 @@
+function removeEmptyProperties(dict) {
+ const noBlanks = Object.entries(dict).reduce((final, [key, value]) => {
+ const upd = { ...final };
+
+ // The number 0 shouldn't be falsey when we're printing variables
+ if (value || value === 0) {
+ upd[key] = value;
+ }
+
+ return upd;
+ }, {});
+
+ return noBlanks;
+}
+
+export function computeSuggestionCommitMessage({ message, values = {} } = {}) {
+ const noEmpties = removeEmptyProperties(values);
+ const matchPhrases = Object.keys(noEmpties)
+ .map((key) => `%{${key}}`)
+ .join('|');
+ const replacementExpression = new RegExp(`(${matchPhrases})`, 'gm');
+
+ return message.replace(replacementExpression, (match) => {
+ const key = match.replace(/(^%{|}$)/gm, '');
+
+ return noEmpties[key];
+ });
+}
diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue
index 03a8a8f9376..df56e6fd8b0 100644
--- a/app/assets/javascripts/notes/components/note_body.vue
+++ b/app/assets/javascripts/notes/components/note_body.vue
@@ -2,6 +2,8 @@
/* eslint-disable vue/no-v-html */
import { mapActions, mapGetters, mapState } from 'vuex';
import $ from 'jquery';
+import { escape } from 'lodash';
+
import '~/behaviors/markdown/render_gfm';
import Suggestions from '~/vue_shared/components/markdown/suggestions.vue';
import autosave from '../mixins/autosave';
@@ -29,6 +31,11 @@ export default {
required: false,
default: null,
},
+ file: {
+ type: Object,
+ required: false,
+ default: null,
+ },
canEdit: {
type: Boolean,
required: true,
@@ -46,6 +53,7 @@ export default {
},
computed: {
...mapGetters(['getDiscussion', 'suggestionsCount']),
+ ...mapGetters('diffs', ['suggestionCommitMessage']),
discussion() {
if (!this.note.isDraft) return {};
@@ -54,7 +62,6 @@ export default {
...mapState({
batchSuggestionsInfo: (state) => state.notes.batchSuggestionsInfo,
}),
- ...mapState('diffs', ['defaultSuggestionCommitMessage']),
noteBody() {
return this.note.note;
},
@@ -64,6 +71,21 @@ export default {
lineType() {
return this.line ? this.line.type : null;
},
+ commitMessage() {
+ // Please see this issue comment for why these
+ // are hard-coded to 1:
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/291027#note_468308022
+ const suggestionsCount = 1;
+ const filesCount = 1;
+ const filePaths = this.file ? [this.file.file_path] : [];
+ const suggestion = this.suggestionCommitMessage({
+ file_paths: filePaths.join(', '),
+ suggestions_count: suggestionsCount,
+ files_count: filesCount,
+ });
+
+ return escape(suggestion);
+ },
},
mounted() {
this.renderGFM();
@@ -135,7 +157,7 @@ export default {
:note-html="note.note_html"
:line-type="lineType"
:help-page-path="helpPagePath"
- :default-commit-message="defaultSuggestionCommitMessage"
+ :default-commit-message="commitMessage"
@apply="applySuggestion"
@applyBatch="applySuggestionBatch"
@addToBatch="addSuggestionToBatch"
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index a1738b993d7..22941857f93 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -431,6 +431,7 @@ export default {
ref="noteBody"
:note="note"
:line="line"
+ :file="diffFile"
:can-edit="note.current_user.can_edit"
:is-editing="isEditing"
:help-page-path="helpPagePath"
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 179e6ef60fb..eb3de936fad 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -243,6 +243,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:domain_denylist_file,
:raw_blob_request_limit,
:issues_create_limit,
+ :notes_create_limit,
:default_branch_name,
disabled_oauth_sign_in_sources: [],
import_sources: [],
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 77fd7688caf..0b1d7d24d21 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -10,6 +10,7 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
+ before_action :create_rate_limit, only: [:create]
feature_category :issue_tracking
@@ -90,4 +91,17 @@ class Projects::NotesController < Projects::ApplicationController
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42383')
end
+
+ def create_rate_limit
+ key = :notes_create
+
+ return unless rate_limiter.throttled?(key, scope: [current_user])
+
+ rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
+ render plain: _('This endpoint has been requested too many times. Try again later.'), status: :too_many_requests
+ end
+
+ def rate_limiter
+ ::Gitlab::ApplicationRateLimiter
+ end
end
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index 2351af01813..ad90e6598c1 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -25,6 +25,7 @@ module Mutations
def resolve(args)
noteable = authorized_find!(id: args[:noteable_id])
+ verify_rate_limit!(current_user)
note = ::Notes::CreateService.new(
noteable.project,
@@ -54,6 +55,14 @@ module Mutations
confidential: args[:confidential]
}
end
+
+ def verify_rate_limit!(current_user)
+ rate_limiter, key = ::Gitlab::ApplicationRateLimiter, :notes_create
+ return unless rate_limiter.throttled?(key, scope: [current_user])
+
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ 'This endpoint has been requested too many times. Try again later.'
+ end
end
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 185c86bd3ca..f92011958dc 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -328,6 +328,7 @@ module ApplicationSettingsHelper
:email_restrictions_enabled,
:email_restrictions,
:issues_create_limit,
+ :notes_create_limit,
:raw_blob_request_limit,
:project_import_limit,
:project_export_limit,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 027cc372ecb..db286005ff4 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -444,6 +444,9 @@ class ApplicationSetting < ApplicationRecord
presence: true,
numericality: { only_integer: true, greater_than: 0 }
+ validates :notes_create_limit,
+ numericality: { only_integer: true, greater_than_or_equal_to: 0 }
+
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 4fca087cf20..9d99b638af6 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -93,6 +93,7 @@ module ApplicationSettingImplementation
import_sources: Settings.gitlab['import_sources'],
invisible_captcha_enabled: false,
issues_create_limit: 300,
+ notes_create_limit: 300,
local_markdown_version: 0,
login_recaptcha_protection_enabled: false,
max_artifacts_size: Settings.artifacts['max_size'],
diff --git a/app/services/concerns/alert_management/alert_processing.rb b/app/services/concerns/alert_management/alert_processing.rb
index cc782bfe7a9..3d64758b11a 100644
--- a/app/services/concerns/alert_management/alert_processing.rb
+++ b/app/services/concerns/alert_management/alert_processing.rb
@@ -125,3 +125,5 @@ module AlertManagement
end
end
end
+
+AlertManagement::AlertProcessing.prepend_ee_mod
diff --git a/app/views/admin/application_settings/_note_limits.html.haml b/app/views/admin/application_settings/_note_limits.html.haml
new file mode 100644
index 00000000000..3045c967b00
--- /dev/null
+++ b/app/views/admin/application_settings/_note_limits.html.haml
@@ -0,0 +1,9 @@
+= form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-note-limits-settings'), html: { class: 'fieldset-form' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ = f.label :notes_create_limit, _('Max requests per minute per user'), class: 'label-bold'
+ = f.number_field :notes_create_limit, class: 'form-control gl-form-input'
+
+ = f.submit _('Save changes'), class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml
index f977a8c93fa..72716e76013 100644
--- a/app/views/admin/application_settings/network.html.haml
+++ b/app/views/admin/application_settings/network.html.haml
@@ -61,6 +61,17 @@
.settings-content
= render 'issue_limits'
+%section.settings.as-note-limits.no-animate#js-note-limits-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Notes Rate Limits')
+ %button.btn.gl-button.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure limit for notes created per minute by web and API requests.')
+ .settings-content
+ = render 'note_limits'
+
%section.settings.as-import-export-limits.no-animate#js-import-export-limits-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml
index 3d6361a90ca..13ae18af2c5 100644
--- a/app/views/doorkeeper/applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/applications/_delete_form.html.haml
@@ -2,7 +2,7 @@
= form_tag oauth_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
- if defined? small
- = button_tag type: "submit", class: "gl-button btn btn-transparent", data: { confirm: _("Are you sure?") } do
+ = button_tag type: "submit", class: "gl-button btn btn-default", data: { confirm: _("Are you sure?") } do
%span.sr-only
= _('Destroy')
= sprite_icon('remove')
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index 2daba4586e1..827a839234f 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -40,8 +40,8 @@
- application.redirect_uri.split.each do |uri|
%div= uri
%td= application.access_tokens.count
- %td
- = link_to edit_oauth_application_path(application), class: "gl-button btn btn-transparent gl-mr-2" do
+ %td.gl-display-flex
+ = link_to edit_oauth_application_path(application), class: "gl-button btn btn-default gl-mr-2" do
%span.sr-only
= _('Edit')
= sprite_icon('pencil')