Commit 96399a81 authored by Patricio Cano's avatar Patricio Cano
Browse files

Allow `Issue` to be submitted as spam

- Added controller actions as reusable concerns
- Added controller tests
parent 32829c302148
......@@ -164,6 +164,10 @@
@include btn-outline($white-light, $orange-normal, $orange-normal, $orange-light, $white-light, $orange-light);
}
&.btn-spam {
@include btn-outline($white-light, $red-normal, $red-normal, $red-light, $white-light, $red-light);
}
&.btn-danger,
&.btn-remove,
&.btn-red {
......
module SpammableActions
extend ActiveSupport::Concern
included do
before_action :authorize_submit_spammable!, only: :mark_as_spam
end
def mark_as_spam
if spammable.submit_spam
spammable.user_agent_detail.update_attribute(:submitted, true)
if spammable.is_a?(Issuable)
SystemNoteService.submit_spam(spammable, spammable.project, current_user)
end
redirect_to spammable, notice: 'Issue was submitted to Akismet successfully.'
else
flash[:error] = 'Error with Akismet. Please check the logs for more info.'
redirect_to spammable
end
end
private
def spammable
raise NotImplementedError
end
def authorize_submit_spammable!
access_denied! unless current_user.admin?
end
end
......@@ -4,6 +4,7 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableActions
include ToggleAwardEmoji
include IssuableCollections
include SpammableActions
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
......@@ -185,6 +186,7 @@ def issue
alias_method :subscribable_resource, :issue
alias_method :issuable, :issue
alias_method :awardable, :issue
alias_method :spammable, :issue
def authorize_read_issue!
return render_404 unless can?(current_user, :read_issue, @issue)
......
......@@ -22,7 +22,7 @@ def attr_spammable(*attrs)
def can_be_submitted?
if user_agent_detail
user_agent_detail.submittable?
user_agent_detail.submittable? && akismet_enabled?
else
false
end
......@@ -41,6 +41,14 @@ def spam?
@spam
end
def submitted?
if user_agent_detail
user_agent_detail.submitted
else
false
end
end
def check_for_spam
self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
end
......@@ -53,17 +61,21 @@ def owner_id
end
end
def to_ability_name
self.class.to_s.underscore
end
# Override this method if an additional check is needed before calling Akismet
def check_for_spam?
akismet_enabled?
end
def spam_title
raise 'Implement in included model!'
raise NotImplementedError
end
def spam_description
raise 'Implement in included model!'
raise NotImplementedError
end
private
......
......@@ -395,6 +395,23 @@ def noteable_moved(noteable, project, noteable_ref, author, direction:)
create_note(noteable: noteable, project: project, author: author, note: body)
end
# Called when the status of a Issuable is submitted as spam
#
# noteable - Noteable object
# project - Project owning noteable
# author - User performing the change
#
# Example Note text:
#
# "Issue submitted as spam."
#
# Returns the created Note object
def submit_spam(noteable, project, author)
body = "Submitted #{noteable.class.to_s.downcase} as spam"
create_note(noteable: noteable, project: project, author: author, note: body)
end
private
def notes_for_mentioner(mentioner, noteable, notes)
......
......@@ -26,7 +26,7 @@
%td
- if spam_log.submitted_as_ham?
.btn.btn-xs.disabled
Submitted as Ham
Submitted as ham
- else
= link_to 'Submit as ham', mark_as_ham_admin_spam_log_path(spam_log), method: :post, class: 'btn btn-xs btn-warning'
- if user && !user.blocked?
......
......@@ -37,14 +37,21 @@
= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
%li
= link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue)
- if @issue.can_be_submitted? && current_user.admin?
- unless @issue.submitted?
%li
= link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'btn-spam', title: 'Submit as spam'
- if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-grouped new-issue-link btn-new btn-inverted', title: 'New issue', id: 'new_issue_link' do
New issue
- if can?(current_user, :update_issue, @issue)
= link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
= link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit' do
Edit
= link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit'
- if @issue.can_be_submitted? && current_user.admin?
- unless @issue.submitted?
= link_to 'Submit as spam', mark_as_spam_namespace_project_issue_path(@project.namespace, @project, @issue), method: :post, class: 'hidden-xs hidden-sm btn btn-grouped btn-spam', title: 'Submit as spam'
.issue-details.issuable-details
......
......@@ -817,6 +817,7 @@
member do
post :toggle_subscription
post :toggle_award_emoji
post :mark_as_spam
get :referenced_merge_requests
get :related_branches
get :can_create_branch
......
......@@ -5,6 +5,7 @@ def change
t.string :ip_address, null: false
t.integer :subject_id, null: false
t.string :subject_type, null: false
t.boolean :submitted, default: false
t.timestamps null: false
end
......
......@@ -1004,6 +1004,7 @@
t.string "ip_address", null: false
t.integer "subject_id", null: false
t.string "subject_type", null: false
t.boolean "submitted", default: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
......
......@@ -34,4 +34,16 @@
expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
end
describe '#mark_as_ham' do
before do
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:ham!).and_return(true)
end
it 'submits the log as ham' do
post :mark_as_ham, id: first_spam.id
expect(response).to have_http_status(302)
expect(SpamLog.find(first_spam.id).submitted_as_ham).to be_truthy
end
end
end
......@@ -322,6 +322,35 @@ def post_new_issue
end
end
describe 'POST #mark_as_spam' do
context 'properly submits to Akismet' do
before do
allow_any_instance_of(Spammable).to receive_messages(can_be_submitted?: true, submit_spam: true)
end
def post_spam
admin = create(:admin)
create(:user_agent_detail, subject: issue)
project.team << [admin, :master]
sign_in(admin)
post :mark_as_spam, {
namespace_id: project.namespace.path,
project_id: project.path,
id: issue.iid
}
end
it 'creates a system note' do
expect{ post_spam }.to change(Note, :count)
end
it 'updates issue' do
post_spam
expect(issue.submitted?).to be_truthy
end
end
end
describe "DELETE #destroy" do
context "when the user is a developer" do
before { sign_in(user) }
......
......@@ -14,6 +14,10 @@
end
describe 'InstanceMethods' do
before do
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:akismet_enabled?).and_return(true)
end
it 'should return the correct creator' do
expect(issue.send(:owner).id).to eq(issue.author_id)
end
......@@ -24,14 +28,11 @@
end
it 'should be submittable' do
create(:user_agent_detail, subject_id: issue.id, subject_type: issue.class.to_s)
create(:user_agent_detail, subject: issue)
expect(issue.can_be_submitted?).to be_truthy
end
describe '#check_for_spam?' do
before do
allow_any_instance_of(Gitlab::AkismetHelper).to receive(:akismet_enabled?).and_return(true)
end
it 'returns true for public project' do
issue.project.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
expect(issue.check_for_spam?).to eq(true)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment