Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
2ace39f2
Commit
2ace39f2
authored
Feb 14, 2017
by
Oswaldo Ferreira
Committed by
Oswaldo Ferreira
Feb 21, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Spam check and reCAPTCHA improvements
parent
88152949
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
935 additions
and
247 deletions
+935
-247
app/controllers/concerns/spammable_actions.rb
app/controllers/concerns/spammable_actions.rb
+24
-6
app/controllers/projects/issues_controller.rb
app/controllers/projects/issues_controller.rb
+9
-25
app/controllers/projects/snippets_controller.rb
app/controllers/projects/snippets_controller.rb
+8
-13
app/controllers/snippets_controller.rb
app/controllers/snippets_controller.rb
+8
-5
app/models/concerns/spammable.rb
app/models/concerns/spammable.rb
+1
-1
app/models/project_snippet.rb
app/models/project_snippet.rb
+0
-4
app/services/create_snippet_service.rb
app/services/create_snippet_service.rb
+6
-4
app/services/issuable_base_service.rb
app/services/issuable_base_service.rb
+18
-14
app/services/issues/create_service.rb
app/services/issues/create_service.rb
+5
-16
app/services/issues/update_service.rb
app/services/issues/update_service.rb
+8
-0
app/services/spam_check_service.rb
app/services/spam_check_service.rb
+24
-0
app/services/spam_service.rb
app/services/spam_service.rb
+22
-9
app/services/update_snippet_service.rb
app/services/update_snippet_service.rb
+8
-2
app/views/layouts/_recaptcha_verification.html.haml
app/views/layouts/_recaptcha_verification.html.haml
+23
-0
app/views/projects/issues/verify.html.haml
app/views/projects/issues/verify.html.haml
+3
-19
app/views/projects/snippets/verify.html.haml
app/views/projects/snippets/verify.html.haml
+4
-0
app/views/snippets/verify.html.haml
app/views/snippets/verify.html.haml
+4
-0
changelogs/unreleased/28093-snippet-and-issue-spam-check-on-edit.yml
...unreleased/28093-snippet-and-issue-spam-check-on-edit.yml
+4
-0
lib/api/helpers.rb
lib/api/helpers.rb
+4
-0
lib/api/issues.rb
lib/api/issues.rb
+5
-1
lib/api/project_snippets.rb
lib/api/project_snippets.rb
+7
-1
lib/api/snippets.rb
lib/api/snippets.rb
+6
-1
lib/api/v3/issues.rb
lib/api/v3/issues.rb
+6
-4
lib/api/v3/project_snippets.rb
lib/api/v3/project_snippets.rb
+7
-1
spec/controllers/projects/issues_controller_spec.rb
spec/controllers/projects/issues_controller_spec.rb
+109
-2
spec/controllers/projects/snippets_controller_spec.rb
spec/controllers/projects/snippets_controller_spec.rb
+165
-21
spec/controllers/snippets_controller_spec.rb
spec/controllers/snippets_controller_spec.rb
+156
-3
spec/models/concerns/spammable_spec.rb
spec/models/concerns/spammable_spec.rb
+1
-0
spec/requests/api/issues_spec.rb
spec/requests/api/issues_spec.rb
+27
-0
spec/requests/api/project_snippets_spec.rb
spec/requests/api/project_snippets_spec.rb
+66
-26
spec/requests/api/snippets_spec.rb
spec/requests/api/snippets_spec.rb
+61
-5
spec/requests/api/v3/issues_spec.rb
spec/requests/api/v3/issues_spec.rb
+27
-0
spec/requests/api/v3/project_snippets_spec.rb
spec/requests/api/v3/project_snippets_spec.rb
+66
-26
spec/services/issues/create_service_spec.rb
spec/services/issues/create_service_spec.rb
+0
-10
spec/services/spam_service_spec.rb
spec/services/spam_service_spec.rb
+43
-28
No files found.
app/controllers/concerns/spammable_actions.rb
View file @
2ace39f2
...
...
@@ -17,13 +17,31 @@ module SpammableActions
private
def
recaptcha_params
return
{}
unless
params
[
:recaptcha_verification
]
&&
Gitlab
::
Recaptcha
.
load_configurations!
&&
verify_recaptcha
def
recaptcha_check_with_fallback
(
&
fallback
)
if
spammable
.
valid?
redirect_to
spammable
elsif
render_recaptcha?
if
params
[
:recaptcha_verification
]
flash
[
:alert
]
=
'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
end
render
:verify
else
fallback
.
call
end
end
def
spammable_params
default_params
=
{
request:
request
}
recaptcha_check
=
params
[
:recaptcha_verification
]
&&
Gitlab
::
Recaptcha
.
load_configurations!
&&
verify_recaptcha
return
default_params
unless
recaptcha_check
{
recaptcha_verified:
true
,
spam_log_id:
params
[
:spam_log_id
]
}
{
recaptcha_verified:
true
,
spam_log_id:
params
[
:spam_log_id
]
}.
merge
(
default_params
)
end
def
spammable
...
...
app/controllers/projects/issues_controller.rb
View file @
2ace39f2
...
...
@@ -94,15 +94,15 @@ class Projects::IssuesController < Projects::ApplicationController
end
def
create
extra_params
=
{
request:
request
,
merge_request_for_resolving_discussions:
merge_request_for_resolving_discussions
}
extra_params
.
merge!
(
recaptcha
_params
)
create_params
=
issue_params
.
merge
(
merge_request_for_resolving_discussions:
merge_request_for_resolving_discussions
)
.
merge
(
spammable
_params
)
@issue
=
Issues
::
CreateService
.
new
(
project
,
current_user
,
issue_params
.
merge
(
extra_params
)
).
execute
@issue
=
Issues
::
CreateService
.
new
(
project
,
current_user
,
create_params
).
execute
respond_to
do
|
format
|
format
.
html
do
html_response_create
recaptcha_check_with_fallback
{
render
:new
}
end
format
.
js
do
@link
=
@issue
.
attachment
.
url
.
to_js
...
...
@@ -111,7 +111,9 @@ class Projects::IssuesController < Projects::ApplicationController
end
def
update
@issue
=
Issues
::
UpdateService
.
new
(
project
,
current_user
,
issue_params
).
execute
(
issue
)
update_params
=
issue_params
.
merge
(
spammable_params
)
@issue
=
Issues
::
UpdateService
.
new
(
project
,
current_user
,
update_params
).
execute
(
issue
)
if
params
[
:move_to_project_id
].
to_i
>
0
new_project
=
Project
.
find
(
params
[
:move_to_project_id
])
...
...
@@ -123,11 +125,7 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to
do
|
format
|
format
.
html
do
if
@issue
.
valid?
redirect_to
issue_path
(
@issue
)
else
render
:edit
end
recaptcha_check_with_fallback
{
render
:edit
}
end
format
.
json
do
...
...
@@ -179,20 +177,6 @@ class Projects::IssuesController < Projects::ApplicationController
protected
def
html_response_create
if
@issue
.
valid?
redirect_to
issue_path
(
@issue
)
elsif
render_recaptcha?
if
params
[
:recaptcha_verification
]
flash
[
:alert
]
=
'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
end
render
:verify
else
render
:new
end
end
def
issue
# The Sortable default scope causes performance issues when used with find_by
@noteable
=
@issue
||=
@project
.
issues
.
where
(
iid:
params
[
:id
]).
reorder
(
nil
).
take
||
redirect_old
...
...
app/controllers/projects/snippets_controller.rb
View file @
2ace39f2
...
...
@@ -38,24 +38,19 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def
create
create_params
=
snippet_params
.
merge
(
request:
request
)
create_params
=
snippet_params
.
merge
(
spammable_params
)
@snippet
=
CreateSnippetService
.
new
(
@project
,
current_user
,
create_params
).
execute
if
@snippet
.
valid?
respond_with
(
@snippet
,
location:
namespace_project_snippet_path
(
@project
.
namespace
,
@project
,
@snippet
))
else
render
:new
end
recaptcha_check_with_fallback
{
render
:new
}
end
def
update
UpdateSnippetService
.
new
(
project
,
current_user
,
@snippet
,
snippet_params
).
execute
respond_with
(
@snippet
,
location:
namespace_project_snippet_path
(
@project
.
namespace
,
@project
,
@snippet
))
update_params
=
snippet_params
.
merge
(
spammable_params
)
UpdateSnippetService
.
new
(
project
,
current_user
,
@snippet
,
update_params
).
execute
recaptcha_check_with_fallback
{
render
:edit
}
end
def
show
...
...
app/controllers/snippets_controller.rb
View file @
2ace39f2
...
...
@@ -42,16 +42,19 @@ class SnippetsController < ApplicationController
end
def
create
create_params
=
snippet_params
.
merge
(
request:
request
)
create_params
=
snippet_params
.
merge
(
spammable_params
)
@snippet
=
CreateSnippetService
.
new
(
nil
,
current_user
,
create_params
).
execute
re
spond_with
@snippet
.
becomes
(
Snippet
)
re
captcha_check_with_fallback
{
render
:new
}
end
def
update
UpdateSnippetService
.
new
(
nil
,
current_user
,
@snippet
,
snippet_params
).
execute
respond_with
@snippet
.
becomes
(
Snippet
)
update_params
=
snippet_params
.
merge
(
spammable_params
)
UpdateSnippetService
.
new
(
nil
,
current_user
,
@snippet
,
update_params
).
execute
recaptcha_check_with_fallback
{
render
:edit
}
end
def
show
...
...
app/models/concerns/spammable.rb
View file @
2ace39f2
...
...
@@ -13,7 +13,7 @@ module Spammable
attr_accessor
:spam
attr_accessor
:spam_log
after_validation
:check_for_spam
,
on:
:create
after_validation
:check_for_spam
,
on:
[
:create
,
:update
]
cattr_accessor
:spammable_attrs
,
instance_accessor:
false
do
[]
...
...
app/models/project_snippet.rb
View file @
2ace39f2
...
...
@@ -9,8 +9,4 @@ class ProjectSnippet < Snippet
participant
:author
participant
:notes_with_associations
def
check_for_spam?
super
&&
project
.
public?
end
end
app/services/create_snippet_service.rb
View file @
2ace39f2
class
CreateSnippetService
<
BaseService
include
SpamCheckService
def
execute
request
=
params
.
delete
(
:request
)
api
=
params
.
delete
(
:api
)
filter_spam_check_params
snippet
=
if
project
project
.
snippets
.
build
(
params
)
...
...
@@ -15,10 +16,11 @@ class CreateSnippetService < BaseService
end
snippet
.
author
=
current_user
snippet
.
spam
=
SpamService
.
new
(
snippet
,
request
).
check
(
api
)
spam_check
(
snippet
,
current_user
)
if
snippet
.
save
UserAgentDetailService
.
new
(
snippet
,
request
).
create
UserAgentDetailService
.
new
(
snippet
,
@
request
).
create
end
snippet
...
...
app/services/issuable_base_service.rb
View file @
2ace39f2
...
...
@@ -191,14 +191,12 @@ class IssuableBaseService < BaseService
# To be overridden by subclasses
end
def
after
_update
(
issuable
)
def
before
_update
(
issuable
)
# To be overridden by subclasses
end
def
update_issuable
(
issuable
,
attributes
)
issuable
.
with_transaction_returning_status
do
issuable
.
update
(
attributes
.
merge
(
updated_by:
current_user
))
end
def
after_update
(
issuable
)
# To be overridden by subclasses
end
def
update
(
issuable
)
...
...
@@ -212,16 +210,22 @@ class IssuableBaseService < BaseService
label_ids
=
process_label_ids
(
params
,
existing_label_ids:
issuable
.
label_ids
)
params
[
:label_ids
]
=
label_ids
if
labels_changing?
(
issuable
.
label_ids
,
label_ids
)
if
params
.
present?
&&
update_issuable
(
issuable
,
params
)
# We do not touch as it will affect a update on updated_at field
ActiveRecord
::
Base
.
no_touching
do
handle_common_system_notes
(
issuable
,
old_labels:
old_labels
)
end
if
params
.
present?
issuable
.
assign_attributes
(
params
.
merge
(
updated_by:
current_user
))
before_update
(
issuable
)
handle_changes
(
issuable
,
old_labels:
old_labels
,
old_mentioned_users:
old_mentioned_users
)
after_update
(
issuable
)
issuable
.
create_new_cross_references!
(
current_user
)
execute_hooks
(
issuable
,
'update'
)
if
issuable
.
with_transaction_returning_status
{
issuable
.
save
}
# We do not touch as it will affect a update on updated_at field
ActiveRecord
::
Base
.
no_touching
do
handle_common_system_notes
(
issuable
,
old_labels:
old_labels
)
end
handle_changes
(
issuable
,
old_labels:
old_labels
,
old_mentioned_users:
old_mentioned_users
)
after_update
(
issuable
)
issuable
.
create_new_cross_references!
(
current_user
)
execute_hooks
(
issuable
,
'update'
)
end
end
issuable
...
...
app/services/issues/create_service.rb
View file @
2ace39f2
module
Issues
class
CreateService
<
Issues
::
BaseService
include
SpamCheckService
def
execute
@request
=
params
.
delete
(
:request
)
@api
=
params
.
delete
(
:api
)
@recaptcha_verified
=
params
.
delete
(
:recaptcha_verified
)
@spam_log_id
=
params
.
delete
(
:spam_log_id
)
filter_spam_check_params
issue_attributes
=
params
.
merge
(
merge_request_for_resolving_discussions:
merge_request_for_resolving_discussions
)
@issue
=
BuildService
.
new
(
project
,
current_user
,
issue_attributes
).
execute
...
...
@@ -12,14 +11,8 @@ module Issues
create
(
@issue
)
end
def
before_create
(
issuable
)
if
@recaptcha_verified
spam_log
=
current_user
.
spam_logs
.
find_by
(
id:
@spam_log_id
,
title:
issuable
.
title
)
spam_log
&
.
update!
(
recaptcha_verified:
true
)
else
issuable
.
spam
=
spam_service
.
check
(
@api
)
issuable
.
spam_log
=
spam_service
.
spam_log
end
def
before_create
(
issue
)
spam_check
(
issue
,
current_user
)
end
def
after_create
(
issuable
)
...
...
@@ -42,10 +35,6 @@ module Issues
private
def
spam_service
@spam_service
||=
SpamService
.
new
(
@issue
,
@request
)
end
def
user_agent_detail_service
UserAgentDetailService
.
new
(
@issue
,
@request
)
end
...
...
app/services/issues/update_service.rb
View file @
2ace39f2
module
Issues
class
UpdateService
<
Issues
::
BaseService
include
SpamCheckService
def
execute
(
issue
)
filter_spam_check_params
update
(
issue
)
end
def
before_update
(
issue
)
spam_check
(
issue
,
current_user
)
end
def
handle_changes
(
issue
,
old_labels:
[],
old_mentioned_users:
[])
if
has_changes?
(
issue
,
old_labels:
old_labels
)
todo_service
.
mark_pending_todos_as_done
(
issue
,
current_user
)
...
...
app/services/spam_check_service.rb
0 → 100644
View file @
2ace39f2
# SpamCheckService
#
# Provide helper methods for checking if a given spammable object has
# potential spam data.
#
# Dependencies:
# - params with :request
#
module
SpamCheckService
def
filter_spam_check_params
@request
=
params
.
delete
(
:request
)
@api
=
params
.
delete
(
:api
)
@recaptcha_verified
=
params
.
delete
(
:recaptcha_verified
)
@spam_log_id
=
params
.
delete
(
:spam_log_id
)
end
def
spam_check
(
spammable
,
user
)
spam_service
=
SpamService
.
new
(
spammable
,
@request
)
spam_service
.
when_recaptcha_verified
(
@recaptcha_verified
,
@api
)
do
user
.
spam_logs
.
find_by
(
id:
@spam_log_id
)
&
.
update!
(
recaptcha_verified:
true
)
end
end
end
app/services/spam_service.rb
View file @
2ace39f2
...
...
@@ -17,15 +17,6 @@ class SpamService
end
end
def
check
(
api
=
false
)
return
false
unless
request
&&
check_for_spam?
return
false
unless
akismet
.
is_spam?
create_spam_log
(
api
)
true
end
def
mark_as_spam!
return
false
unless
spammable
.
submittable_as_spam?
...
...
@@ -36,8 +27,30 @@ class SpamService
end
end
def
when_recaptcha_verified
(
recaptcha_verified
,
api
=
false
)
# In case it's a request which is already verified through recaptcha, yield
# block.
if
recaptcha_verified
yield
else
# 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.
spammable
.
spam
=
check
(
api
)
spammable
.
spam_log
=
spam_log
end
end
private
def
check
(
api
)
return
false
unless
request
&&
check_for_spam?
return
false
unless
akismet
.
is_spam?
create_spam_log
(
api
)
true
end
def
akismet
@akismet
||=
AkismetService
.
new
(
spammable_owner
,
...
...
app/services/update_snippet_service.rb
View file @
2ace39f2
class
UpdateSnippetService
<
BaseService
include
SpamCheckService
attr_accessor
:snippet
def
initialize
(
project
,
user
,
snippet
,
params
)
...
...
@@ -9,7 +11,7 @@ class UpdateSnippetService < BaseService
def
execute
# check that user is allowed to set specified visibility_level
new_visibility
=
params
[
:visibility_level
]
if
new_visibility
&&
new_visibility
.
to_i
!=
snippet
.
visibility_level
unless
Gitlab
::
VisibilityLevel
.
allowed_for?
(
current_user
,
new_visibility
)
deny_visibility_level
(
snippet
,
new_visibility
)
...
...
@@ -17,6 +19,10 @@ class UpdateSnippetService < BaseService
end
end
snippet
.
update_attributes
(
params
)
filter_spam_check_params
snippet
.
assign_attributes
(
params
)
spam_check
(
snippet
,
current_user
)
snippet
.
save
end
end
app/views/layouts/_recaptcha_verification.html.haml
0 → 100644
View file @
2ace39f2
-
humanized_resource_name
=
spammable
.
class
.
model_name
.
human
.
downcase
-
resource_name
=
spammable
.
class
.
model_name
.
singular
%h3
.page-title
Anti-spam verification
%hr
%p
#{
"We detected potential spam in the #{humanized_resource_name}. Please solve the reCAPTCHA to proceed."
}
=
form_for
form
do
|
f
|
.recaptcha
-
params
[
resource_name
].
each
do
|
field
,
value
|
=
hidden_field
(
resource_name
,
field
,
value:
value
)
=
hidden_field_tag
(
:spam_log_id
,
spammable
.
spam_log
.
id
)
=
hidden_field_tag
(
:recaptcha_verification
,
true
)
=
recaptcha_tags
-# Yields a block with given extra params.
=
yield
.row-content-block.footer-block
=
f
.
submit
"Submit
#{
humanized_resource_name
}
"
,
class:
'btn btn-create'
app/views/projects/issues/verify.html.haml
View file @
2ace39f2
-
page_title
"Anti-spam verification"
-
form
=
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
@issue
]
%h3
.page-title
Anti-spam verification
%hr
%p
We detected potential spam in the issue description. Please verify that you are not a robot to submit the issue.
=
form_for
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
@issue
]
do
|
f
|
.recaptcha
-
params
[
:issue
].
each
do
|
field
,
value
|
=
hidden_field
(
:issue
,
field
,
value:
value
)
=
hidden_field_tag
(
:merge_request_for_resolving_discussions
,
params
[
:merge_request_for_resolving_discussions
])
=
hidden_field_tag
(
:spam_log_id
,
@issue
.
spam_log
.
id
)
=
hidden_field_tag
(
:recaptcha_verification
,
true
)
=
recaptcha_tags
.row-content-block.footer-block
=
f
.
submit
"Submit
#{
@issue
.
class
.
model_name
.
human
.
downcase
}
"
,
class:
'btn btn-create'
=
render
layout:
'layouts/recaptcha_verification'
,
locals:
{
spammable:
@issue
,
form:
form
}
do
=
hidden_field_tag
(
:merge_request_for_resolving_discussions
,
params
[
:merge_request_for_resolving_discussions
])
app/views/projects/snippets/verify.html.haml
0 → 100644
View file @
2ace39f2
-
form
=
[
@project
.
namespace
.
becomes
(
Namespace
),
@project
,
@snippet
.
becomes
(
Snippet
)]
=
render
'layouts/recaptcha_verification'
,
spammable:
@snippet
,
form:
form
app/views/snippets/verify.html.haml
0 → 100644
View file @
2ace39f2
-
form
=
[
@snippet
.
becomes
(
Snippet
)]
=
render
'layouts/recaptcha_verification'
,
spammable:
@snippet
,
form:
form
changelogs/unreleased/28093-snippet-and-issue-spam-check-on-edit.yml
0 → 100644
View file @
2ace39f2
---
title
:
Spam check and reCAPTCHA improvements
merge_request
:
author
:
lib/api/helpers.rb
View file @
2ace39f2
...
...
@@ -215,6 +215,10 @@ module API
end
end
def
render_spam_error!
render_api_error!
({
error:
'Spam detected'
},
400
)
end
def
render_api_error!
(
message
,
status
)
error!
({
'message'
=>
message
},
status
,
header
)
end
...
...
lib/api/issues.rb
View file @
2ace39f2
...
...
@@ -169,9 +169,13 @@ module API
params
.
delete
(
:updated_at
)
end
update_params
=
declared_params
(
include_missing:
false
).
merge
(
request:
request
,
api:
true
)
issue
=
::
Issues
::
UpdateService
.
new
(
user_project
,
current_user
,
declared_params
(
include_missing:
false
)).
execute
(
issue
)
update_params
).
execute
(
issue
)
render_spam_error!
if
issue
.
spam?
if
issue
.
valid?
present
issue
,
with:
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
...
...
lib/api/project_snippets.rb
View file @
2ace39f2
...
...
@@ -63,6 +63,8 @@ module API
snippet
=
CreateSnippetService
.
new
(
user_project
,
current_user
,
snippet_params
).
execute
render_spam_error!
if
snippet
.
spam?
if
snippet
.
persisted?
present
snippet
,
with:
Entities
::
ProjectSnippet
else
...
...
@@ -92,12 +94,16 @@ module API
authorize!
:update_project_snippet
,
snippet
snippet_params
=
declared_params
(
include_missing:
false
)
.
merge
(
request:
request
,
api:
true
)
snippet_params
[
:content
]
=
snippet_params
.
delete
(
:code
)
if
snippet_params
[
:code
].
present?
UpdateSnippetService
.
new
(
user_project
,
current_user
,
snippet
,
snippet_params
).
execute
if
snippet
.
persisted?
render_spam_error!
if
snippet
.
spam?
if
snippet
.
valid?
present
snippet
,
with:
Entities
::
ProjectSnippet
else
render_validation_error!
(
snippet
)
...
...
lib/api/snippets.rb
View file @
2ace39f2
...
...
@@ -67,6 +67,8 @@ module API
attrs
=
declared_params
(
include_missing:
false
).
merge
(
request:
request
,
api:
true
)
snippet
=
CreateSnippetService
.
new
(
nil
,
current_user
,
attrs
).
execute
render_spam_error!
if
snippet
.
spam?
if
snippet
.
persisted?
present
snippet
,
with:
Entities
::
PersonalSnippet
else
...
...
@@ -93,9 +95,12 @@ module API
return
not_found!
(
'Snippet'
)
unless
snippet
authorize!
:update_personal_snippet
,
snippet
attrs
=
declared_params
(
include_missing:
false
)
attrs
=
declared_params
(
include_missing:
false
)
.
merge
(
request:
request
,
api:
true
)
UpdateSnippetService
.
new
(
nil
,
current_user
,
snippet
,
attrs
).
execute
render_spam_error!
if
snippet
.
spam?
if
snippet
.
persisted?
present
snippet
,
with:
Entities
::
PersonalSnippet
else
...
...
lib/api/v3/issues.rb
View file @
2ace39f2
...
...
@@ -149,9 +149,7 @@ module API
issue
=
::
Issues
::
CreateService
.
new
(
user_project
,
current_user
,
issue_params
.
merge
(
request:
request
,
api:
true
)).
execute
if
issue
.
spam?
render_api_error!
({
error:
'Spam detected'
},
400
)
end
render_spam_error!
if
issue
.
spam?
if
issue
.
valid?
present
issue
,
with:
::
API
::
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
...
...
@@ -182,9 +180,13 @@ module API
params
.
delete
(
:updated_at
)
end
update_params
=
declared_params
(
include_missing:
false
).
merge
(
request:
request
,
api:
true
)
issue
=
::
Issues
::
UpdateService
.
new
(
user_project
,
current_user
,
declared_params
(
include_missing:
false
)).
execute
(
issue
)
update_params
).
execute
(
issue
)
render_spam_error!
if
issue
.
spam?
if
issue
.
valid?
present
issue
,
with:
::
API
::
Entities
::
Issue
,
current_user:
current_user
,
project:
user_project
...
...
lib/api/v3/project_snippets.rb
View file @
2ace39f2
...
...
@@ -64,6 +64,8 @@ module API
snippet
=
CreateSnippetService
.
new
(
user_project
,
current_user
,
snippet_params
).
execute
render_spam_error!
if
snippet
.
spam?
if
snippet
.
persisted?
present
snippet
,
with:
::
API
::
V3
::
Entities
::
ProjectSnippet
else
...
...
@@ -93,12 +95,16 @@ module API
authorize!
:update_project_snippet
,
snippet
snippet_params
=
declared_params
(
include_missing:
false
)
.
merge
(
request:
request
,
api:
true
)
snippet_params
[
:content
]
=
snippet_params
.
delete
(
:code
)
if
snippet_params
[
:code
].
present?
UpdateSnippetService
.
new
(
user_project
,
current_user
,
snippet
,
snippet_params
).
execute
if
snippet
.
persisted?
render_spam_error!
if
snippet
.
spam?
if
snippet
.
valid?
present
snippet
,
with:
::
API
::
V3
::
Entities
::
ProjectSnippet
else
render_validation_error!
(
snippet
)
...
...
spec/controllers/projects/issues_controller_spec.rb
View file @
2ace39f2
...
...
@@ -152,6 +152,113 @@ describe Projects::IssuesController do
end
end
context
'Akismet is enabled'
do
let
(
:project
)
{
create
(
:project_empty_repo
,
:public
)
}
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
allow_any_instance_of
(
SpamService
).
to
receive
(
:check_for_spam?
).
and_return
(
true
)
end
context
'when an issue is not identified as spam'
do
before
do
allow_any_instance_of
(
described_class
).
to
receive
(
:verify_recaptcha
).
and_return
(
false
)
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
false
)
end
it
'normally updates the issue'
do
expect
{
update_issue
(
title:
'Foo'
)
}.
to
change
{
issue
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when an issue is identified as spam'
do
before
{
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
}
context
'when captcha is not verified'
do
def
update_spam_issue
update_issue
(
title:
'Spam Title'
,
description:
'Spam lives here'
)
end
before
{
allow_any_instance_of
(
described_class
).
to
receive
(
:verify_recaptcha
).
and_return
(
false
)
}
it
'rejects an issue recognized as a spam'
do
expect
{
update_spam_issue
}.
not_to
change
{
issue
.
reload
.
title
}
end
it
'rejects an issue recognized as a spam when recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
expect
{
update_spam_issue
}.
not_to
change
{
issue
.
reload
.
title
}
end
it
'creates a spam log'
do
update_spam_issue
spam_logs
=
SpamLog
.
all
expect
(
spam_logs
.
count
).
to
eq
(
1
)
expect
(
spam_logs
.
first
.
title
).
to
eq
(
'Spam Title'
)
expect
(
spam_logs
.
first
.
recaptcha_verified
).
to
be_falsey
end
it
'renders verify template'
do
update_spam_issue
expect
(
response
).
to
render_template
(
:verify
)
end
end
context
'when captcha is verified'
do
let
(
:spammy_title
)
{
'Whatever'
}
let!
(
:spam_logs
)
{
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
}
def
update_verified_issue
update_issue
({
title:
spammy_title
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
end
before
do
allow_any_instance_of
(
described_class
).
to
receive
(
:verify_recaptcha
)
.
and_return
(
true
)
end
it
'redirect to issue page'
do
update_verified_issue
expect
(
response
).
to
redirect_to
(
namespace_project_issue_path
(
project
.
namespace
,
project
,
issue
))
end
it
'accepts an issue after recaptcha is verified'
do
expect
{
update_verified_issue
}.
to
change
{
issue
.
reload
.
title
}.
to
(
spammy_title
)
end
it
'marks spam log as recaptcha_verified'
do
expect
{
update_verified_issue
}.
to
change
{
SpamLog
.
last
.
recaptcha_verified
}.
from
(
false
).
to
(
true
)
end
it
'does not mark spam log as recaptcha_verified when it does not belong to current_user'
do
spam_log
=
create
(
:spam_log
)
expect
{
update_issue
(
spam_log_id:
spam_log
.
id
,
recaptcha_verification:
true
)
}.
not_to
change
{
SpamLog
.
last
.
recaptcha_verified
}
end
end
end
end
def
update_issue
(
issue_params
=
{},
additional_params
=
{})
params
=
{
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
.
to_param
,
id:
issue
.
iid
,
issue:
issue_params
}.
merge
(
additional_params
)
put
:update
,
params
end
def
move_issue
put
:update
,
namespace_id:
project
.
namespace
.
to_param
,
...
...
@@ -384,7 +491,7 @@ describe Projects::IssuesController do
allow_any_instance_of
(
SpamService
).
to
receive
(
:check_for_spam?
).
and_return
(
true
)
end
context
'when an issue is not identified as
a
spam'
do
context
'when an issue is not identified as spam'
do
before
do
allow_any_instance_of
(
described_class
).
to
receive
(
:verify_recaptcha
).
and_return
(
false
)
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
false
)
...
...
@@ -395,7 +502,7 @@ describe Projects::IssuesController do
end
end
context
'when an issue is identified as
a
spam'
do
context
'when an issue is identified as spam'
do
before
{
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
}
context
'when captcha is not verified'
do
...
...
spec/controllers/projects/snippets_controller_spec.rb
View file @
2ace39f2
...
...
@@ -70,7 +70,7 @@ describe Projects::SnippetsController do
end
describe
'POST #create'
do
def
create_snippet
(
project
,
snippet_params
=
{})
def
create_snippet
(
project
,
snippet_params
=
{}
,
additional_params
=
{}
)
sign_in
(
user
)
project
.
add_developer
(
user
)
...
...
@@ -79,7 +79,7 @@ describe Projects::SnippetsController do
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
.
to_param
,
project_snippet:
{
title:
'Title'
,
content:
'Content'
}.
merge
(
snippet_params
)
}
}
.
merge
(
additional_params
)
end
context
'when the snippet is spam'
do
...
...
@@ -87,35 +87,179 @@ describe Projects::SnippetsController do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the project is private'
do
let
(
:private_project
)
{
create
(
:project_empty_repo
,
:private
)
}
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
end
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
render_template
(
:new
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :new with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:new
)
end
context
'when the snippet is public'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
private_project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
create_snippet
(
project
,
{
visibility_level:
Snippet
::
PUBLIC
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
Snippet
.
last
)
end
end
end
end
end
describe
'PUT #update'
do
let
(
:project
)
{
create
:project
,
:public
}
let
(
:snippet
)
{
create
:project_snippet
,
author:
user
,
project:
project
,
visibility_level:
visibility_level
}
def
update_snippet
(
snippet_params
=
{},
additional_params
=
{})
sign_in
(
user
)
project
.
add_developer
(
user
)
put
:update
,
{
namespace_id:
project
.
namespace
.
to_param
,
project_id:
project
.
to_param
,
id:
snippet
.
id
,
project_snippet:
{
title:
'Title'
,
content:
'Content'
}.
merge
(
snippet_params
)
}.
merge
(
additional_params
)
snippet
.
reload
end
context
'when the snippet is spam'
do
before
do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the snippet is private'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'updates the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
snippet
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when the project is public'
do
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
context
'when the snippet is public'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
it
'rejects the shippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :edit with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
update_snippet
(
title:
'Foo'
)
expect
(
response
).
to
render_template
(
:edit
)
end
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
update_snippet
(
title:
'Foo'
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
snippet
=
update_snippet
({
title:
spammy_title
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
snippet
)
end
end
end
context
'when the private snippet is made public'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'rejects the shippet'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :edit with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
render_template
(
:new
)
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:edit
)
end
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
snippet
=
update_snippet
({
title:
spammy_title
,
visibility_level:
Snippet
::
PUBLIC
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
snippet
)
end
end
end
...
...
spec/controllers/snippets_controller_spec.rb
View file @
2ace39f2
...
...
@@ -139,12 +139,14 @@ describe SnippetsController do
end
describe
'POST #create'
do
def
create_snippet
(
snippet_params
=
{})
def
create_snippet
(
snippet_params
=
{}
,
additional_params
=
{}
)
sign_in
(
user
)
post
:create
,
{
personal_snippet:
{
title:
'Title'
,
content:
'Content'
}.
merge
(
snippet_params
)
}
}.
merge
(
additional_params
)
Snippet
.
last
end
context
'when the snippet is spam'
do
...
...
@@ -163,13 +165,164 @@ describe SnippetsController do
it
'rejects the shippet'
do
expect
{
create_snippet
(
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
render_template
(
:new
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :new with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
create_snippet
(
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:new
)
end
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
create_snippet
(
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
snippet
=
create_snippet
({
title:
spammy_title
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
snippet_path
(
snippet
))
end
end
end
end
end
describe
'PUT #update'
do
let
(
:project
)
{
create
:project
}
let
(
:snippet
)
{
create
:personal_snippet
,
author:
user
,
project:
project
,
visibility_level:
visibility_level
}
def
update_snippet
(
snippet_params
=
{},
additional_params
=
{})
sign_in
(
user
)
put
:update
,
{
id:
snippet
.
id
,
personal_snippet:
{
title:
'Title'
,
content:
'Content'
}.
merge
(
snippet_params
)
}.
merge
(
additional_params
)
snippet
.
reload
end
context
'when the snippet is spam'
do
before
do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the snippet is private'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'updates the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
snippet
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when a private snippet is made public'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :edit with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:edit
)
end
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
snippet
=
update_snippet
({
title:
spammy_title
,
visibility_level:
Snippet
::
PUBLIC
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
snippet
)
end
end
end
context
'when the snippet is public'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
it
'rejects the shippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'renders :edit with recaptcha disabled'
do
stub_application_setting
(
recaptcha_enabled:
false
)
update_snippet
(
title:
'Foo'
)
expect
(
response
).
to
render_template
(
:edit
)
end
context
'recaptcha enabled'
do
before
do
stub_application_setting
(
recaptcha_enabled:
true
)
end
it
'renders :verify with recaptcha enabled'
do
update_snippet
(
title:
'Foo'
)
expect
(
response
).
to
render_template
(
:verify
)
end
it
'renders snippet page when recaptcha verified'
do
spammy_title
=
'Whatever'
spam_logs
=
create_list
(
:spam_log
,
2
,
user:
user
,
title:
spammy_title
)
snippet
=
update_snippet
({
title:
spammy_title
},
{
spam_log_id:
spam_logs
.
last
.
id
,
recaptcha_verification:
true
})
expect
(
response
).
to
redirect_to
(
snippet_path
(
snippet
))
end
end
end
end
end
...
...
spec/models/concerns/spammable_spec.rb
View file @
2ace39f2
...
...
@@ -23,6 +23,7 @@ describe Issue, 'Spammable' do
describe
'#check_for_spam?'
do
it
'returns true for public project'
do
issue
.
project
.
update_attribute
(
:visibility_level
,
Gitlab
::
VisibilityLevel
::
PUBLIC
)
expect
(
issue
.
check_for_spam?
).
to
eq
(
true
)
end
...
...
spec/requests/api/issues_spec.rb
View file @
2ace39f2
...
...
@@ -1028,6 +1028,33 @@ describe API::Issues, api: true do
end
end
describe
'PUT /projects/:id/issues/:issue_id with spam filtering'
do
let
(
:params
)
do
{
title:
'updated title'
,
description:
'content here'
,
labels:
'label, label2'
}
end
it
"does not create a new project issue"
do
allow_any_instance_of
(
SpamService
).
to
receive_messages
(
check_for_spam?:
true
)
allow_any_instance_of
(
AkismetService
).
to
receive_messages
(
is_spam?:
true
)
put
api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
params
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
spam_logs
=
SpamLog
.
all
expect
(
spam_logs
.
count
).
to
eq
(
1
)
expect
(
spam_logs
[
0
].
title
).
to
eq
(
'updated title'
)
expect
(
spam_logs
[
0
].
description
).
to
eq
(
'content here'
)
expect
(
spam_logs
[
0
].
user
).
to
eq
(
user
)
expect
(
spam_logs
[
0
].
noteable_type
).
to
eq
(
'Issue'
)
end
end
describe
'PUT /projects/:id/issues/:issue_id to update labels'
do
let!
(
:label
)
{
create
(
:label
,
title:
'dummy'
,
project:
project
)
}
let!
(
:label_link
)
{
create
(
:label_link
,
label:
label
,
target:
issue
)
}
...
...
spec/requests/api/project_snippets_spec.rb
View file @
2ace39f2
...
...
@@ -78,43 +78,33 @@ describe API::ProjectSnippets, api: true do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the project is private'
do
let
(
:private_project
)
{
create
(
:project_empty_repo
,
:private
)
}
context
'when the snippet is public'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
private_project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
end
context
'when the project is public'
do
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
end
end
describe
'PUT /projects/:project_id/snippets/:id/'
do
let
(
:snippet
)
{
create
(
:project_snippet
,
author:
admin
)
}
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
let
(
:snippet
)
{
create
(
:project_snippet
,
author:
admin
,
visibility_level:
visibility_level
)
}
it
'updates snippet'
do
new_content
=
'New content'
...
...
@@ -138,6 +128,56 @@ describe API::ProjectSnippets, api: true do
expect
(
response
).
to
have_http_status
(
400
)
end
context
'when the snippet is spam'
do
def
update_snippet
(
snippet_params
=
{})
put
api
(
"/projects/
#{
snippet
.
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
admin
),
snippet_params
end
before
do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the snippet is private'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'creates the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
snippet
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when the snippet is public'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
context
'when the private snippet is made public'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
snippet
.
reload
.
title
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
end
end
describe
'DELETE /projects/:project_id/snippets/:id/'
do
...
...
spec/requests/api/snippets_spec.rb
View file @
2ace39f2
...
...
@@ -129,7 +129,9 @@ describe API::Snippets, api: true do
it
'rejects the shippet'
do
expect
{
create_snippet
(
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
it
'creates a spam log'
do
...
...
@@ -141,16 +143,20 @@ describe API::Snippets, api: true do
end
describe
'PUT /snippets/:id'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
let
(
:other_user
)
{
create
(
:user
)
}
let
(
:public_snippet
)
{
create
(
:personal_snippet
,
:public
,
author:
user
)
}
let
(
:snippet
)
do
create
(
:personal_snippet
,
author:
user
,
visibility_level:
visibility_level
)
end
it
'updates snippet'
do
new_content
=
'New content'
put
api
(
"/snippets/
#{
public_
snippet
.
id
}
"
,
user
),
content:
new_content
put
api
(
"/snippets/
#{
snippet
.
id
}
"
,
user
),
content:
new_content
expect
(
response
).
to
have_http_status
(
200
)
public_
snippet
.
reload
expect
(
public_
snippet
.
content
).
to
eq
(
new_content
)
snippet
.
reload
expect
(
snippet
.
content
).
to
eq
(
new_content
)
end
it
'returns 404 for invalid snippet id'
do
...
...
@@ -161,7 +167,7 @@ describe API::Snippets, api: true do
end
it
"returns 404 for another user's snippet"
do
put
api
(
"/snippets/
#{
public_
snippet
.
id
}
"
,
other_user
),
title:
'fubar'
put
api
(
"/snippets/
#{
snippet
.
id
}
"
,
other_user
),
title:
'fubar'
expect
(
response
).
to
have_http_status
(
404
)
expect
(
json_response
[
'message'
]).
to
eq
(
'404 Snippet Not Found'
)
...
...
@@ -172,6 +178,56 @@ describe API::Snippets, api: true do
expect
(
response
).
to
have_http_status
(
400
)
end
context
'when the snippet is spam'
do
def
update_snippet
(
snippet_params
=
{})
put
api
(
"/snippets/
#{
snippet
.
id
}
"
,
user
),
snippet_params
end
before
do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the snippet is private'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'updates the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
snippet
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when the snippet is public'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
it
'rejects the shippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
not_to
change
{
snippet
.
reload
.
title
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
context
'when a private snippet is made public'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
end
end
describe
'DELETE /snippets/:id'
do
...
...
spec/requests/api/v3/issues_spec.rb
View file @
2ace39f2
...
...
@@ -986,6 +986,33 @@ describe API::V3::Issues, api: true do
end
end
describe
'PUT /projects/:id/issues/:issue_id with spam filtering'
do
let
(
:params
)
do
{
title:
'updated title'
,
description:
'content here'
,
labels:
'label, label2'
}
end
it
"does not create a new project issue"
do
allow_any_instance_of
(
SpamService
).
to
receive_messages
(
check_for_spam?:
true
)
allow_any_instance_of
(
AkismetService
).
to
receive_messages
(
is_spam?:
true
)
put
v3_api
(
"/projects/
#{
project
.
id
}
/issues/
#{
issue
.
id
}
"
,
user
),
params
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
spam_logs
=
SpamLog
.
all
expect
(
spam_logs
.
count
).
to
eq
(
1
)
expect
(
spam_logs
[
0
].
title
).
to
eq
(
'updated title'
)
expect
(
spam_logs
[
0
].
description
).
to
eq
(
'content here'
)
expect
(
spam_logs
[
0
].
user
).
to
eq
(
user
)
expect
(
spam_logs
[
0
].
noteable_type
).
to
eq
(
'Issue'
)
end
end
describe
'PUT /projects/:id/issues/:issue_id to update labels'
do
let!
(
:label
)
{
create
(
:label
,
title:
'dummy'
,
project:
project
)
}
let!
(
:label_link
)
{
create
(
:label_link
,
label:
label
,
target:
issue
)
}
...
...
spec/requests/api/v3/project_snippets_spec.rb
View file @
2ace39f2
...
...
@@ -85,43 +85,33 @@ describe API::ProjectSnippets, api: true do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the project is private'
do
let
(
:private_project
)
{
create
(
:project_empty_repo
,
:private
)
}
context
'when the snippet is public'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
private_project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
end
context
'when the project is public'
do
context
'when the snippet is private'
do
it
'creates the snippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PRIVATE
)
}.
to
change
{
Snippet
.
count
}.
by
(
1
)
end
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
context
'when the snippet is public'
do
it
'rejects the shippet'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
Snippet
.
count
}
expect
(
response
).
to
have_http_status
(
400
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
it
'creates a spam log'
do
expect
{
create_snippet
(
project
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
end
end
describe
'PUT /projects/:project_id/snippets/:id/'
do
let
(
:snippet
)
{
create
(
:project_snippet
,
author:
admin
)
}
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
let
(
:snippet
)
{
create
(
:project_snippet
,
author:
admin
,
visibility_level:
visibility_level
)
}
it
'updates snippet'
do
new_content
=
'New content'
...
...
@@ -145,6 +135,56 @@ describe API::ProjectSnippets, api: true do
expect
(
response
).
to
have_http_status
(
400
)
end
context
'when the snippet is spam'
do
def
update_snippet
(
snippet_params
=
{})
put
v3_api
(
"/projects/
#{
snippet
.
project
.
id
}
/snippets/
#{
snippet
.
id
}
"
,
admin
),
snippet_params
end
before
do
allow_any_instance_of
(
AkismetService
).
to
receive
(
:is_spam?
).
and_return
(
true
)
end
context
'when the snippet is private'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'creates the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
snippet
.
reload
.
title
}.
to
(
'Foo'
)
end
end
context
'when the snippet is public'
do
let
(
:visibility_level
)
{
Snippet
::
PUBLIC
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
not_to
change
{
snippet
.
reload
.
title
}
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
context
'when the private snippet is made public'
do
let
(
:visibility_level
)
{
Snippet
::
PRIVATE
}
it
'rejects the snippet'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
not_to
change
{
snippet
.
reload
.
title
}
expect
(
response
).
to
have_http_status
(
400
)
expect
(
json_response
[
'message'
]).
to
eq
({
"error"
=>
"Spam detected"
})
end
it
'creates a spam log'
do
expect
{
update_snippet
(
title:
'Foo'
,
visibility_level:
Snippet
::
PUBLIC
)
}.
to
change
{
SpamLog
.
count
}.
by
(
1
)
end
end
end
end
describe
'DELETE /projects/:project_id/snippets/:id/'
do
...
...
spec/services/issues/create_service_spec.rb
View file @
2ace39f2
...
...
@@ -230,16 +230,6 @@ describe Issues::CreateService, services: true do
expect
{
issue
}.
not_to
change
{
SpamLog
.
last
.
recaptcha_verified
}
end
end
context
'when spam log title does not match the issue title'
do
before
do
opts
[
:title
]
=
'Another issue'
end
it
'does not mark spam_log as recaptcha_verified'
do
expect
{
issue
}.
not_to
change
{
SpamLog
.
last
.
recaptcha_verified
}
end
end
end
context
'when recaptcha was not verified'
do
...
...
spec/services/spam_service_spec.rb
View file @
2ace39f2
require
'spec_helper'
describe
SpamService
,
services:
true
do
describe
'#check'
do
let
(
:project
)
{
create
(
:project
,
:public
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:request
)
{
double
(
:request
,
env:
{})
}
describe
'#when_recaptcha_verified'
do
def
check_spam
(
issue
,
request
,
recaptcha_verified
)
described_class
.
new
(
issue
,
request
).
when_recaptcha_verified
(
recaptcha_verified
)
do
'yielded'
end
end
it
'yields block when recaptcha was already verified'
do
issue
=
build_stubbed
(
:issue
)
def
check_spam
(
issue
,
request
)
described_class
.
new
(
issue
,
request
).
check
expect
(
check_spam
(
issue
,
nil
,
true
)).
to
eql
(
'yielded'
)
end
context
'when indicated as spam by akismet'
do
before
{
allow
(
AkismetService
).
to
receive
(
:new
).
and_return
(
double
(
is_spam?:
true
))
}
context
'when recaptcha was not verified'
do
let
(
:project
)
{
create
(
:project
,
:public
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:request
)
{
double
(
:request
,
env:
{})
}
it
'returns false when request is missing'
do
expect
(
check_spam
(
issue
,
nil
)).
to
be_falsey
end
context
'when indicated as spam by akismet'
do
before
{
allow
(
AkismetService
).
to
receive
(
:new
).
and_return
(
double
(
is_spam?:
true
))
}
it
'returns false when issue is not public
'
do
issue
=
create
(
:issue
,
project:
create
(
:project
,
:private
)
)
it
'doesnt check as spam when request is missing
'
do
check_spam
(
issue
,
nil
,
false
)
expect
(
check_spam
(
issue
,
request
)
).
to
be_falsey
end
expect
(
issue
.
spam
).
to
be_falsey
end
it
'returns true'
do
expect
(
check_spam
(
issue
,
request
)).
to
be_truthy
end
it
'checks as spam'
do
check_spam
(
issue
,
request
,
false
)
it
'creates a spam log'
do
expect
{
check_spam
(
issue
,
request
)
}.
to
change
{
SpamLog
.
count
}.
from
(
0
).
to
(
1
)
end
end
expect
(
issue
.
spam
).
to
be_truthy
end
context
'when not indicated as spam by akismet'
do
before
{
allow
(
AkismetService
).
to
receive
(
:new
).
and_return
(
double
(
is_spam?:
false
))
}
it
'creates a spam log'
do
expect
{
check_spam
(
issue
,
request
,
false
)
}
.
to
change
{
SpamLog
.
count
}.
from
(
0
).
to
(
1
)
end
it
'returns false'
do
expect
(
check_spam
(
issue
,
request
)).
to
be_falsey
it
'doesnt yield block'
do
expect
(
check_spam
(
issue
,
request
,
false
))
.
to
eql
(
SpamLog
.
last
)
end
end
it
'does not create a spam log'
do
expect
{
check_spam
(
issue
,
request
)
}.
not_to
change
{
SpamLog
.
count
}
context
'when not indicated as spam by akismet'
do
before
{
allow
(
AkismetService
).
to
receive
(
:new
).
and_return
(
double
(
is_spam?:
false
))
}
it
'returns false'
do
expect
(
check_spam
(
issue
,
request
,
false
)).
to
be_falsey
end
it
'does not create a spam log'
do
expect
{
check_spam
(
issue
,
request
,
false
)
}
.
not_to
change
{
SpamLog
.
count
}
end
end
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment