Skip to content
Snippets Groups Projects
Commit 7bb7a8d5 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 504ab1e3
No related branches found
No related tags found
No related merge requests found
Showing
with 429 additions and 113 deletions
Loading
@@ -42,6 +42,7 @@ export default {
Loading
@@ -42,6 +42,7 @@ export default {
:width="imgSize" :width="imgSize"
:class="`s${imgSize}`" :class="`s${imgSize}`"
class="avatar avatar-inline m-0" class="avatar avatar-inline m-0"
data-qa-selector="avatar_image"
/> />
<i v-if="hasMergeIcon" aria-hidden="true" class="fa fa-exclamation-triangle merge-icon"></i> <i v-if="hasMergeIcon" aria-hidden="true" class="fa fa-exclamation-triangle merge-icon"></i>
</span> </span>
Loading
Loading
Loading
@@ -32,13 +32,14 @@ export default {
Loading
@@ -32,13 +32,14 @@ export default {
}; };
</script> </script>
<template> <template>
<div class="title hide-collapsed"> <div class="title hide-collapsed" data-qa-selector="assignee_title">
{{ assigneeTitle }} {{ assigneeTitle }}
<i v-if="loading" aria-hidden="true" class="fa fa-spinner fa-spin block-loading"></i> <i v-if="loading" aria-hidden="true" class="fa fa-spinner fa-spin block-loading"></i>
<a <a
v-if="editable" v-if="editable"
class="js-sidebar-dropdown-toggle edit-link float-right" class="js-sidebar-dropdown-toggle edit-link float-right"
href="#" href="#"
data-qa-selector="assignee_edit_link"
data-track-event="click_edit_button" data-track-event="click_edit_button"
data-track-label="right_sidebar" data-track-label="right_sidebar"
data-track-property="assignee" data-track-property="assignee"
Loading
Loading
Loading
@@ -85,7 +85,12 @@ export default {
Loading
@@ -85,7 +85,12 @@ export default {
</div> </div>
</div> </div>
<div v-if="renderShowMoreSection" class="user-list-more"> <div v-if="renderShowMoreSection" class="user-list-more">
<button type="button" class="btn-link" @click="toggleShowLess"> <button
type="button"
class="btn-link"
data-qa-selector="more_assignees_link"
@click="toggleShowLess"
>
<template v-if="showLess"> <template v-if="showLess">
{{ hiddenAssigneesLabel }} {{ hiddenAssigneesLabel }}
</template> </template>
Loading
Loading
Loading
@@ -76,7 +76,7 @@ module ProjectsHelper
Loading
@@ -76,7 +76,7 @@ module ProjectsHelper
link_to(author_html, user_path(author), class: "author-link js-user-link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}", data: data_attrs).html_safe link_to(author_html, user_path(author), class: "author-link js-user-link #{"#{opts[:extra_class]}" if opts[:extra_class]} #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}", data: data_attrs).html_safe
else else
title = opts[:title].sub(":name", sanitize(author.name)) title = opts[:title].sub(":name", sanitize(author.name))
link_to(author_html, user_path(author), class: "author-link has-tooltip", title: title, data: { container: 'body' }).html_safe link_to(author_html, user_path(author), class: "author-link has-tooltip", title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe
end end
end end
   
Loading
Loading
Loading
@@ -80,4 +80,9 @@ module Spammable
Loading
@@ -80,4 +80,9 @@ module Spammable
def check_for_spam? def check_for_spam?
true true
end end
# Override in Spammable if differs
def allow_possible_spam?
Feature.enabled?(:allow_possible_spam, project)
end
end end
Loading
@@ -14,6 +14,7 @@ class Snippet < ApplicationRecord
Loading
@@ -14,6 +14,7 @@ class Snippet < ApplicationRecord
include Editable include Editable
include Gitlab::SQL::Pattern include Gitlab::SQL::Pattern
include FromUnion include FromUnion
extend ::Gitlab::Utils::Override
   
cache_markdown_field :title, pipeline: :single_line cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description cache_markdown_field :description
Loading
@@ -191,6 +192,12 @@ class Snippet < ApplicationRecord
Loading
@@ -191,6 +192,12 @@ class Snippet < ApplicationRecord
(public? && (title_changed? || content_changed?)) (public? && (title_changed? || content_changed?))
end end
   
# snippers are the biggest sources of spam
override :allow_possible_spam?
def allow_possible_spam?
false
end
def spammable_entity_type def spammable_entity_type
'snippet' 'snippet'
end end
Loading
Loading
Loading
@@ -37,7 +37,8 @@ class SpamService
Loading
@@ -37,7 +37,8 @@ class SpamService
else else
# Otherwise, it goes to Akismet and check if it's a spam. If that's the # Otherwise, it goes to Akismet and check if it's a spam. If that's the
# case, it assigns spammable record as "spam" and create a SpamLog record. # case, it assigns spammable record as "spam" and create a SpamLog record.
spammable.spam = check(api) possible_spam = check(api)
spammable.spam = possible_spam unless spammable.allow_possible_spam?
spammable.spam_log = spam_log spammable.spam_log = spam_log
end end
end end
Loading
Loading
Loading
@@ -7,4 +7,4 @@
Loading
@@ -7,4 +7,4 @@
= link_to_member(@project, assignee, name: false, title: "Assigned to :name") = link_to_member(@project, assignee, name: false, title: "Assigned to :name")
   
- if more_assignees_count.positive? - if more_assignees_count.positive?
%span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', 'original-title' => "+#{more_assignees_count} more assignees" } } +#{more_assignees_count} %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', 'original-title' => "+#{more_assignees_count} more assignees", qa_selector: 'avatar_counter' } } +#{more_assignees_count}
Loading
@@ -313,17 +313,22 @@ Developer documentation][mdn].
Loading
@@ -313,17 +313,22 @@ Developer documentation][mdn].
   
## Updating the PO files with the new content ## Updating the PO files with the new content
   
Now that the new content is marked for translation, we need to update the PO Now that the new content is marked for translation, we need to update
files with the following command: `locale/gitlab.pot` files with the following command:
   
```sh ```sh
bin/rake gettext:regenerate bin/rake gettext:regenerate
``` ```
   
This command will update the `locale/gitlab.pot` file with the newly externalized This command will update `locale/gitlab.pot` file with the newly externalized
strings and remove any strings that aren't used anymore. You should check this strings and remove any strings that aren't used anymore. You should check this
file in. Once the changes are on master, they will be picked up by file in. Once the changes are on master, they will be picked up by
[Crowdin](http://translate.gitlab.com) and be presented for translation. [Crowdin](http://translate.gitlab.com) and be presented for
translation.
We don't need to check in any changes to the
`locale/[language]/gitlab.po` files. Those will be updated in a [when
translations from Crowdin are merged](merging_translations.md).
   
If there are merge conflicts in the `gitlab.pot` file, you can delete the file If there are merge conflicts in the `gitlab.pot` file, you can delete the file
and regenerate it using the same command. and regenerate it using the same command.
Loading
Loading
Loading
@@ -293,7 +293,7 @@ The applications below can be uninstalled.
Loading
@@ -293,7 +293,7 @@ The applications below can be uninstalled.
| ----------- | -------------- | ----- | | ----------- | -------------- | ----- |
| Cert-Manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html) or [revoke your certificates](https://letsencrypt.org/docs/revoking/) | | Cert-Manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html) or [revoke your certificates](https://letsencrypt.org/docs/revoking/) |
| GitLab Runner | 12.2+ | Any running pipelines will be canceled. | | GitLab Runner | 12.2+ | Any running pipelines will be canceled. |
| Helm | 12.2+ | The associated Tiller pod will be deleted and cannot be restored. | | Helm | 12.2+ | The associated Tiller pod, the `gitlab-managed-apps` namespace, and all of its resources will be deleted and cannot be restored. |
| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. | | Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
| JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. | | JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. |
| Knative | 12.1+ | The associated IP will be deleted and cannot be restored. | | Knative | 12.1+ | The associated IP will be deleted and cannot be restored. |
Loading
Loading
Loading
@@ -131,6 +131,10 @@ module QA
Loading
@@ -131,6 +131,10 @@ module QA
has_no_css?('.fa-spinner', wait: Capybara.default_max_wait_time) has_no_css?('.fa-spinner', wait: Capybara.default_max_wait_time)
end end
   
def finished_loading_block?
has_no_css?('.fa-spinner.block-loading', wait: Capybara.default_max_wait_time)
end
def wait_for_animated_element(name) def wait_for_animated_element(name)
# It would be ideal if we could detect when the animation is complete # It would be ideal if we could detect when the animation is complete
# but in some cases there's nothing we can easily access via capybara # but in some cases there's nothing we can easily access via capybara
Loading
Loading
Loading
@@ -5,14 +5,30 @@ module QA
Loading
@@ -5,14 +5,30 @@ module QA
module Project module Project
module Issue module Issue
class Index < Page::Base class Index < Page::Base
view 'app/helpers/projects_helper.rb' do
element :assignee_link
end
view 'app/views/projects/issues/_issue.html.haml' do view 'app/views/projects/issues/_issue.html.haml' do
element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern element :issue_link, 'link_to issue.title' # rubocop:disable QA/ElementWithPattern
end end
   
view 'app/views/shared/issuable/_assignees.html.haml' do
element :avatar_counter
end
view 'app/views/shared/issuable/_nav.html.haml' do view 'app/views/shared/issuable/_nav.html.haml' do
element :closed_issues_link element :closed_issues_link
end end
   
def assignee_link_count
all_elements(:assignee_link).count
end
def avatar_counter
find_element(:avatar_counter)
end
def click_issue_link(title) def click_issue_link(title)
click_link(title) click_link(title)
end end
Loading
Loading
Loading
@@ -22,24 +22,54 @@ module QA
Loading
@@ -22,24 +22,54 @@ module QA
element :noteable_note_item element :noteable_note_item
end end
   
view 'app/assets/javascripts/sidebar/components/assignees/assignee_avatar.vue' do
element :avatar_image
end
view 'app/assets/javascripts/sidebar/components/assignees/assignee_title.vue' do
element :assignee_edit_link
element :assignee_title
end
view 'app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue' do
element :more_assignees_link
end
view 'app/helpers/dropdowns_helper.rb' do view 'app/helpers/dropdowns_helper.rb' do
element :dropdown_input_field element :dropdown_input_field
end end
   
view 'app/views/shared/notes/_form.html.haml' do view 'app/views/shared/issuable/_close_reopen_button.html.haml' do
element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern element :reopen_issue_button
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end end
   
view 'app/views/shared/issuable/_sidebar.html.haml' do view 'app/views/shared/issuable/_sidebar.html.haml' do
element :assignee_block
element :labels_block element :labels_block
element :edit_link_labels element :edit_link_labels
element :dropdown_menu_labels element :dropdown_menu_labels
element :milestone_link element :milestone_link
end end
   
view 'app/views/shared/issuable/_close_reopen_button.html.haml' do view 'app/views/shared/notes/_form.html.haml' do
element :reopen_issue_button element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end
def assign(user)
click_element(:assignee_edit_link)
select_user(user.username)
click_body
end
def assignee_title
find_element(:assignee_title)
end
def avatar_image_count
wait_assignees_block_finish_loading do
all_elements(:avatar_image).count
end
end end
   
def click_milestone_link def click_milestone_link
Loading
@@ -66,6 +96,10 @@ module QA
Loading
@@ -66,6 +96,10 @@ module QA
end end
end end
   
def more_assignees_link
find_element(:more_assignees_link)
end
def select_all_activities_filter def select_all_activities_filter
select_filter_with_text('Show all activity') select_filter_with_text('Show all activity')
end end
Loading
@@ -103,6 +137,10 @@ module QA
Loading
@@ -103,6 +137,10 @@ module QA
find_element(:labels_block) find_element(:labels_block)
end end
   
def toggle_more_assignees_link
click_element(:more_assignees_link)
end
private private
   
def select_filter_with_text(text) def select_filter_with_text(text)
Loading
@@ -112,6 +150,20 @@ module QA
Loading
@@ -112,6 +150,20 @@ module QA
find_element(:filter_options, text: text).click find_element(:filter_options, text: text).click
end end
end end
def select_user(username)
find("#{element_selector_css(:assignee_block)} input").set(username)
find('.dropdown-menu-user-link', text: "@#{username}").click
end
def wait_assignees_block_finish_loading
within_element(:assignee_block) do
wait(reload: false, max: 10, interval: 1) do
finished_loading_block?
yield
end
end
end
end end
end end
end end
Loading
Loading
Loading
@@ -145,6 +145,38 @@ module QA
Loading
@@ -145,6 +145,38 @@ module QA
ENV['GITLAB_QA_PASSWORD_2'] ENV['GITLAB_QA_PASSWORD_2']
end end
   
def gitlab_qa_username_3
ENV['GITLAB_QA_USERNAME_3'] || 'gitlab-qa-user3'
end
def gitlab_qa_password_3
ENV['GITLAB_QA_PASSWORD_3']
end
def gitlab_qa_username_4
ENV['GITLAB_QA_USERNAME_4'] || 'gitlab-qa-user4'
end
def gitlab_qa_password_4
ENV['GITLAB_QA_PASSWORD_4']
end
def gitlab_qa_username_5
ENV['GITLAB_QA_USERNAME_5'] || 'gitlab-qa-user5'
end
def gitlab_qa_password_5
ENV['GITLAB_QA_PASSWORD_5']
end
def gitlab_qa_username_6
ENV['GITLAB_QA_USERNAME_6'] || 'gitlab-qa-user6'
end
def gitlab_qa_password_6
ENV['GITLAB_QA_PASSWORD_6']
end
def knapsack? def knapsack?
!!(ENV['KNAPSACK_GENERATE_REPORT'] || ENV['KNAPSACK_REPORT_PATH'] || ENV['KNAPSACK_TEST_FILE_PATTERN']) !!(ENV['KNAPSACK_GENERATE_REPORT'] || ENV['KNAPSACK_REPORT_PATH'] || ENV['KNAPSACK_TEST_FILE_PATTERN'])
end end
Loading
Loading
Loading
@@ -408,6 +408,7 @@ describe Projects::IssuesController do
Loading
@@ -408,6 +408,7 @@ describe Projects::IssuesController do
   
context 'when user has access to update issue' do context 'when user has access to update issue' do
before do before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
project.add_developer(user) project.add_developer(user)
end end
   
Loading
@@ -421,14 +422,30 @@ describe Projects::IssuesController do
Loading
@@ -421,14 +422,30 @@ describe Projects::IssuesController do
context 'when Akismet is enabled and the issue is identified as spam' do context 'when Akismet is enabled and the issue is identified as spam' do
before do before do
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true) expect(akismet_service).to receive_messages(spam?: true)
end
end
context 'when allow_possible_spam feature flag is false' do
before do
stub_feature_flags(allow_possible_spam: false)
end
it 'renders json with recaptcha_html' do
subject
expect(json_response).to have_key('recaptcha_html')
end
end end
   
it 'renders json with recaptcha_html' do context 'when allow_possible_spam feature flag is true' do
subject it 'updates the issue' do
subject
   
expect(json_response).to have_key('recaptcha_html') expect(response).to have_http_status(:ok)
expect(issue.reload.title).to eq('New title')
end
end end
end end
end end
Loading
@@ -681,13 +698,13 @@ describe Projects::IssuesController do
Loading
@@ -681,13 +698,13 @@ describe Projects::IssuesController do
before do before do
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
end end
   
context 'when an issue is not identified as spam' do context 'when an issue is not identified as spam' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false) expect(akismet_service).to receive_messages(spam?: false)
end
end end
   
it 'normally updates the issue' do it 'normally updates the issue' do
Loading
@@ -696,45 +713,64 @@ describe Projects::IssuesController do
Loading
@@ -696,45 +713,64 @@ describe Projects::IssuesController do
end end
   
context 'when an issue is identified as spam' do context 'when an issue is identified as spam' do
before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
end
context 'when captcha is not verified' do context 'when captcha is not verified' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
   
it 'rejects an issue recognized as a spam' do context 'when allow_possible_spam feature flag is false' do
expect { update_issue }.not_to change { issue.reload.title } before do
end stub_feature_flags(allow_possible_spam: false)
end
   
it 'rejects an issue recognized as a spam when recaptcha disabled' do it 'rejects an issue recognized as a spam' do
stub_application_setting(recaptcha_enabled: false) expect { update_issue }.not_to change { issue.reload.title }
end
   
expect { update_issue }.not_to change { issue.reload.title } it 'rejects an issue recognized as a spam when recaptcha disabled' do
end stub_application_setting(recaptcha_enabled: false)
   
it 'creates a spam log' do expect { update_issue }.not_to change { issue.reload.title }
update_issue(issue_params: { title: 'Spam title' }) end
   
spam_logs = SpamLog.all it 'creates a spam log' do
expect { update_issue(issue_params: { title: 'Spam title' }) }
.to log_spam(title: 'Spam title', noteable_type: 'Issue')
end
   
expect(spam_logs.count).to eq(1) it 'renders recaptcha_html json response' do
expect(spam_logs.first.title).to eq('Spam title') update_issue
expect(spam_logs.first.recaptcha_verified).to be_falsey
end expect(json_response).to have_key('recaptcha_html')
end
   
it 'renders recaptcha_html json response' do it 'returns 200 status' do
update_issue update_issue
   
expect(json_response).to have_key('recaptcha_html') expect(response).to have_gitlab_http_status(200)
end
end end
   
it 'returns 200 status' do context 'when allow_possible_spam feature flag is true' do
update_issue it 'updates the issue recognized as spam' do
expect { update_issue }.to change { issue.reload.title }
end
   
expect(response).to have_gitlab_http_status(200) it 'creates a spam log' do
expect { update_issue(issue_params: { title: 'Spam title' }) }
.to log_spam(
title: 'Spam title', description: issue.description,
noteable_type: 'Issue', recaptcha_verified: false
)
end
it 'returns 200 status' do
update_issue
expect(response).to have_gitlab_http_status(200)
end
end end
end end
   
Loading
@@ -748,11 +784,6 @@ describe Projects::IssuesController do
Loading
@@ -748,11 +784,6 @@ describe Projects::IssuesController do
additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true }) additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true })
end end
   
before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha)
.and_return(true)
end
it 'returns 200 status' do it 'returns 200 status' do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
end end
Loading
@@ -917,55 +948,72 @@ describe Projects::IssuesController do
Loading
@@ -917,55 +948,72 @@ describe Projects::IssuesController do
context 'Akismet is enabled' do context 'Akismet is enabled' do
before do before do
stub_application_setting(recaptcha_enabled: true) stub_application_setting(recaptcha_enabled: true)
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
end end
   
context 'when an issue is not identified as spam' do context 'when an issue is not identified as spam' do
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) stub_feature_flags(allow_possible_spam: false)
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(false)
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: false)
end
end end
   
it 'does not create an issue' do it 'creates an issue' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count) expect { post_new_issue(title: 'Some title') }.to change(Issue, :count)
end end
end end
   
context 'when an issue is identified as spam' do context 'when an issue is identified as spam' do
before do
allow_any_instance_of(AkismetService).to receive(:spam?).and_return(true)
end
context 'when captcha is not verified' do context 'when captcha is not verified' do
def post_spam_issue def post_spam_issue
post_new_issue(title: 'Spam Title', description: 'Spam lives here') post_new_issue(title: 'Spam Title', description: 'Spam lives here')
end end
   
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false) expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
   
it 'rejects an issue recognized as a spam' do context 'when allow_possible_spam feature flag is false' do
expect { post_spam_issue }.not_to change(Issue, :count) before do
end stub_feature_flags(allow_possible_spam: false)
end
   
it 'creates a spam log' do it 'rejects an issue recognized as a spam' do
post_spam_issue expect { post_spam_issue }.not_to change(Issue, :count)
spam_logs = SpamLog.all end
   
expect(spam_logs.count).to eq(1) it 'creates a spam log' do
expect(spam_logs.first.title).to eq('Spam Title') expect { post_spam_issue }
expect(spam_logs.first.recaptcha_verified).to be_falsey .to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
end end
   
it 'does not create an issue when it is not valid' do it 'does not create an issue when it is not valid' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count) expect { post_new_issue(title: '') }.not_to change(Issue, :count)
end
it 'does not create an issue when recaptcha is not enabled' do
stub_application_setting(recaptcha_enabled: false)
expect { post_spam_issue }.not_to change(Issue, :count)
end
end end
   
it 'does not create an issue when recaptcha is not enabled' do context 'when allow_possible_spam feature flag is true' do
stub_application_setting(recaptcha_enabled: false) it 'creates an issue recognized as spam' do
expect { post_spam_issue }.to change(Issue, :count)
end
   
expect { post_spam_issue }.not_to change(Issue, :count) it 'creates a spam log' do
expect { post_spam_issue }
.to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
end
it 'does not create an issue when it is not valid' do
expect { post_new_issue(title: '') }.not_to change(Issue, :count)
end
end end
end end
   
Loading
@@ -977,7 +1025,7 @@ describe Projects::IssuesController do
Loading
@@ -977,7 +1025,7 @@ describe Projects::IssuesController do
end end
   
before do before do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(true) expect(controller).to receive_messages(verify_recaptcha: true)
end end
   
it 'accepts an issue after recaptcha is verified' do it 'accepts an issue after recaptcha is verified' do
Loading
@@ -1030,8 +1078,12 @@ describe Projects::IssuesController do
Loading
@@ -1030,8 +1078,12 @@ describe Projects::IssuesController do
describe 'POST #mark_as_spam' do describe 'POST #mark_as_spam' do
context 'properly submits to Akismet' do context 'properly submits to Akismet' do
before do before do
allow_any_instance_of(AkismetService).to receive_messages(submit_spam: true) expect_next_instance_of(AkismetService) do |akismet_service|
allow_any_instance_of(ApplicationSetting).to receive_messages(akismet_enabled: true) expect(akismet_service).to receive_messages(submit_spam: true)
end
expect_next_instance_of(ApplicationSetting) do |setting|
expect(setting).to receive_messages(akismet_enabled: true)
end
end end
   
def post_spam def post_spam
Loading
@@ -1266,7 +1318,9 @@ describe Projects::IssuesController do
Loading
@@ -1266,7 +1318,9 @@ describe Projects::IssuesController do
end end
   
it "shows error when upload fails" do it "shows error when upload fails" do
allow_any_instance_of(UploadService).to receive(:execute).and_return(nil) expect_next_instance_of(UploadService) do |upload_service|
expect(upload_service).to receive(:execute).and_return(nil)
end
   
import_csv import_csv
   
Loading
Loading
Loading
@@ -111,7 +111,7 @@ describe Projects::SnippetsController do
Loading
@@ -111,7 +111,7 @@ describe Projects::SnippetsController do
   
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(project, visibility_level: Snippet::PUBLIC) } expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Title', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
   
it 'renders :new with recaptcha disabled' do it 'renders :new with recaptcha disabled' do
Loading
@@ -192,7 +192,7 @@ describe Projects::SnippetsController do
Loading
@@ -192,7 +192,7 @@ describe Projects::SnippetsController do
   
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect { update_snippet(title: 'Foo') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
   
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
Loading
@@ -237,7 +237,7 @@ describe Projects::SnippetsController do
Loading
@@ -237,7 +237,7 @@ describe Projects::SnippetsController do
   
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) } expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
end end
   
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
Loading
Loading
Loading
@@ -269,7 +269,7 @@ describe SnippetsController do
Loading
@@ -269,7 +269,7 @@ describe SnippetsController do
   
it 'creates a spam log' do it 'creates a spam log' do
expect { create_snippet(visibility_level: Snippet::PUBLIC) } expect { create_snippet(visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Title', user: user, noteable_type: 'PersonalSnippet')
end end
   
it 'renders :new with recaptcha disabled' do it 'renders :new with recaptcha disabled' do
Loading
@@ -345,7 +345,7 @@ describe SnippetsController do
Loading
@@ -345,7 +345,7 @@ describe SnippetsController do
   
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) } expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
end end
   
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
Loading
@@ -389,8 +389,8 @@ describe SnippetsController do
Loading
@@ -389,8 +389,8 @@ describe SnippetsController do
end end
   
it 'creates a spam log' do it 'creates a spam log' do
expect { update_snippet(title: 'Foo') } expect {update_snippet(title: 'Foo') }
.to change { SpamLog.count }.by(1) .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
end end
   
it 'renders :edit with recaptcha disabled' do it 'renders :edit with recaptcha disabled' do
Loading
Loading
Loading
@@ -30,21 +30,47 @@ describe 'New issue', :js do
Loading
@@ -30,21 +30,47 @@ describe 'New issue', :js do
visit new_project_issue_path(project) visit new_project_issue_path(project)
end end
   
it 'creates an issue after solving reCaptcha' do context 'when allow_possible_spam feature flag is false' do
fill_in 'issue_title', with: 'issue title' before do
fill_in 'issue_description', with: 'issue description' stub_feature_flags(allow_possible_spam: false)
end
   
click_button 'Submit issue' it 'creates an issue after solving reCaptcha' do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
   
# it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha click_button 'Submit issue'
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
   
click_button 'Submit issue' # it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('issue title')
expect(page).to have_css('.recaptcha')
   
expect(page.find('.issue-details h2.title')).to have_content('issue title') click_button 'Submit issue'
expect(page.find('.issue-details .description')).to have_content('issue description')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
end
context 'when allow_possible_spam feature flag is true' do
before do
fill_in 'issue_title', with: 'issue title'
fill_in 'issue_description', with: 'issue description'
end
it 'creates an issue without a need to solve reCaptcha' do
click_button 'Submit issue'
expect(page).not_to have_css('.recaptcha')
expect(page.find('.issue-details h2.title')).to have_content('issue title')
expect(page.find('.issue-details .description')).to have_content('issue description')
end
it 'creates a spam log record' do
expect { click_button 'Submit issue' }
.to log_spam(title: 'issue title', description: 'issue description', user_id: user.id, noteable_type: 'Issue')
end
end end
end end
   
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe 'User creates snippet', :js do
let(:user) { create(:user) }
before do
stub_feature_flags(allow_possible_spam: false)
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
Gitlab::CurrentSettings.update!(
akismet_enabled: true,
akismet_api_key: 'testkey',
recaptcha_enabled: true,
recaptcha_site_key: 'test site key',
recaptcha_private_key: 'test private key'
)
sign_in(user)
visit new_snippet_path
fill_in 'personal_snippet_title', with: 'My Snippet Title'
fill_in 'personal_snippet_description', with: 'My Snippet **Description**'
find('#personal_snippet_visibility_level_20').set(true)
page.within('.file-editor') do
find('.ace_text-input', visible: false).send_keys 'Hello World!'
end
end
shared_examples 'solve recaptcha' do
it 'creates a snippet after solving reCaptcha' do
click_button('Create snippet')
wait_for_requests
# it is impossible to test recaptcha automatically and there is no possibility to fill in recaptcha
# recaptcha verification is skipped in test environment and it always returns true
expect(page).not_to have_content('My Snippet Title')
expect(page).to have_css('.recaptcha')
click_button('Submit personal snippet')
expect(page).to have_content('My Snippet Title')
end
end
context 'when identified as a spam' do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "true", status: 200)
end
context 'when allow_possible_spam feature flag is false' do
it_behaves_like 'solve recaptcha'
end
context 'when allow_possible_spam feature flag is true' do
it_behaves_like 'solve recaptcha'
end
end
context 'when not identified as a spam' do
before do
WebMock.stub_request(:any, /.*akismet.com.*/).to_return(body: "false", status: 200)
end
it 'creates a snippet' do
click_button('Create snippet')
wait_for_requests
expect(page).not_to have_css('.recaptcha')
expect(page).to have_content('My Snippet Title')
end
end
end
Loading
@@ -374,9 +374,17 @@ describe API::Issues do
Loading
@@ -374,9 +374,17 @@ describe API::Issues do
end end
   
describe 'POST /projects/:id/issues with spam filtering' do describe 'POST /projects/:id/issues with spam filtering' do
def post_issue
post api("/projects/#{project.id}/issues", user), params: params
end
before do before do
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true) expect_next_instance_of(SpamService) do |spam_service|
allow_any_instance_of(AkismetService).to receive_messages(spam?: true) expect(spam_service).to receive_messages(check_for_spam?: true)
end
expect_next_instance_of(AkismetService) do |akismet_service|
expect(akismet_service).to receive_messages(spam?: true)
end
end end
   
let(:params) do let(:params) do
Loading
@@ -387,17 +395,43 @@ describe API::Issues do
Loading
@@ -387,17 +395,43 @@ describe API::Issues do
} }
end end
   
it 'does not create a new project issue' do context 'when allow_possible_spam feature flag is false' do
expect { post api("/projects/#{project.id}/issues", user), params: params }.not_to change(Issue, :count) before do
expect(response).to have_gitlab_http_status(400) stub_feature_flags(allow_possible_spam: false)
expect(json_response['message']).to eq({ 'error' => 'Spam detected' }) end
spam_logs = SpamLog.all it 'does not create a new project issue' do
expect(spam_logs.count).to eq(1) expect { post_issue }.not_to change(Issue, :count)
expect(spam_logs[0].title).to eq('new issue') end
expect(spam_logs[0].description).to eq('content here')
expect(spam_logs[0].user).to eq(user) it 'returns correct status and message' do
expect(spam_logs[0].noteable_type).to eq('Issue') post_issue
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq({ 'error' => 'Spam detected' })
end
it 'creates a new spam log entry' do
expect { post_issue }
.to log_spam(title: 'new issue', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end
context 'when allow_possible_spam feature flag is true' do
it 'does creates a new project issue' do
expect { post_issue }.to change(Issue, :count).by(1)
end
it 'returns correct status' do
post_issue
expect(response).to have_gitlab_http_status(201)
end
it 'creates a new spam log entry' do
expect { post_issue }
.to log_spam(title: 'new issue', description: 'content here', user_id: user.id, noteable_type: 'Issue')
end
end end
end end
   
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment