Commit f0adf28e authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Merge branch 'event-create-service' into 'master'

EventCreateService class

The goal is to collect all event creation logic in one place called EventCreateService.
Because now its placed in observers, controllers, services etc
parents 05c9ab94 535339a6
......@@ -47,14 +47,6 @@ class Event < ActiveRecord::Base
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
class << self
def determine_action(record)
if [Issue, MergeRequest].include? record.class
Event::CREATED
elsif record.kind_of? Note
Event::COMMENTED
end
end
def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
commit = project.repository.commit(ref.target)
......
class ActivityObserver < BaseObserver
observe :issue, :note, :milestone
def after_create(record)
if record.kind_of?(Note)
# Skip system notes, like status changes and cross-references.
return true if record.system?
# Skip wall notes to prevent spamming of dashboard
return true if record.noteable_type.blank?
end
create_event(record, Event.determine_action(record)) if current_user
end
def after_close(record, transition)
create_event(record, Event::CLOSED)
end
def after_reopen(record, transition)
create_event(record, Event::REOPENED)
end
protected
def create_event(record, status)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
end
......@@ -3,6 +3,10 @@ def notification
NotificationService.new
end
def event_service
EventCreateService.new
end
def log_info message
Gitlab::AppLogger.info message
end
......
class IssueObserver < BaseObserver
def after_create(issue)
notification.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
issue.create_cross_references!(issue.project, current_user)
execute_hooks(issue)
end
def after_close(issue, transition)
notification.close_issue(issue, current_user)
event_service.close_issue(issue, current_user)
create_note(issue)
execute_hooks(issue)
end
def after_reopen(issue, transition)
event_service.reopen_issue(issue, current_user)
create_note(issue)
execute_hooks(issue)
end
......
class MergeRequestObserver < ActivityObserver
observe :merge_request
class MergeRequestObserver < BaseObserver
def after_create(merge_request)
if merge_request.author_id
create_event(merge_request, Event.determine_action(merge_request))
end
event_service.open_mr(merge_request, current_user)
notification.new_merge_request(merge_request, current_user)
merge_request.create_cross_references!(merge_request.project, current_user)
execute_hooks(merge_request)
end
def after_close(merge_request, transition)
create_event(merge_request, Event::CLOSED)
event_service.close_mr(merge_request, current_user)
notification.close_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
end
def after_reopen(merge_request, transition)
create_event(merge_request, Event::REOPENED)
event_service.reopen_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
merge_request.reload_code
......@@ -33,16 +28,6 @@ def after_update(merge_request)
execute_hooks(merge_request)
end
def create_event(record, status)
Event.create(
project: record.target_project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
private
# Create merge request note with service comment like 'Status changed to closed'
......
class MilestoneObserver < BaseObserver
def after_create(milestone)
event_service.open_milestone(milestone, current_user)
end
def after_close(milestone, transition)
event_service.close_milestone(milestone, current_user)
end
def after_reopen(milestone, transition)
event_service.reopen_milestone(milestone, current_user)
end
end
......@@ -2,6 +2,12 @@ class NoteObserver < BaseObserver
def after_create(note)
notification.new_note(note)
# Skip system notes, like status changes and cross-references.
# Skip wall notes to prevent spamming of dashboard
if note.noteable_type.present? && !note.system
event_service.leave_note(note, current_user)
end
unless note.system?
# Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit.
......
# EventCreateService class
#
# Used for creating events feed on dashboard after certain user action
#
# Ex.
# EventCreateService.new.new_issue(issue, current_user)
#
class EventCreateService
def open_issue(issue, current_user)
create_event(issue, current_user, Event::CREATED)
end
def close_issue(issue, current_user)
create_event(issue, current_user, Event::CLOSED)
end
def reopen_issue(issue, current_user)
create_event(issue, current_user, Event::REOPENED)
end
def open_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::CREATED)
end
def close_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::CLOSED)
end
def reopen_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::REOPENED)
end
def merge_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::MERGED)
end
def open_milestone(milestone, current_user)
create_event(milestone, current_user, Event::CREATED)
end
def close_milestone(milestone, current_user)
create_event(milestone, current_user, Event::CLOSED)
end
def reopen_milestone(milestone, current_user)
create_event(milestone, current_user, Event::REOPENED)
end
def leave_note(note, current_user)
create_event(note, current_user, Event::COMMENTED)
end
private
def create_event(record, current_user, status)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
end
......@@ -8,13 +8,7 @@ def notification
end
def create_merge_event(merge_request, current_user)
Event.create(
project: merge_request.target_project,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Event::MERGED,
author_id: current_user.id
)
EventCreateService.new.merge_mr(merge_request, current_user)
end
def execute_project_hooks(merge_request)
......
......@@ -19,7 +19,7 @@ class Application < Rails::Application
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
config.active_record.observers = :activity_observer,
config.active_record.observers = :milestone_observer,
:project_activity_cache_observer,
:issue_observer,
:key_observer,
......
require 'spec_helper'
describe ActivityObserver do
let(:project) { create(:project) }
before { Thread.current[:current_user] = create(:user) }
def self.it_should_be_valid_event
it { @event.should_not be_nil }
it { @event.project.should == project }
end
describe "Issue created" do
before do
Issue.observers.enable :activity_observer do
@issue = create(:issue, project: project)
@event = Event.last
end
end
it_should_be_valid_event
it { @event.action.should == Event::CREATED }
it { @event.target.should == @issue }
end
describe "Issue commented" do
before do
Note.observers.enable :activity_observer do
@issue = create(:issue, project: project)
@note = create(:note, noteable: @issue, project: project, author: @issue.author)
@event = Event.last
end
end
it_should_be_valid_event
it { @event.action.should == Event::COMMENTED }
it { @event.target.should == @note }
end
describe "Ignore system notes" do
let(:author) { create(:user) }
let!(:issue) { create(:issue, project: project) }
let!(:other) { create(:issue) }
it "should not create events for status change notes" do
expect do
Note.observers.enable :activity_observer do
Note.create_status_change_note(issue, project, author, 'reopened', nil)
end
end.to_not change { Event.count }
end
it "should not create events for cross-reference notes" do
expect do
Note.observers.enable :activity_observer do
Note.create_cross_reference_note(issue, other, author, issue.project)
end
end.to_not change { Event.count }
end
end
end
......@@ -100,16 +100,4 @@
response.status.should == 405
end
end
describe "PUT /projects/:id/issues/:issue_id to test observer on close" do
before { enable_observers }
after { disable_observers }
it "should create an activity event when an issue is closed" do
Event.should_receive(:create)
put api("/projects/#{project.id}/issues/#{issue.id}", user),
state_event: "close"
end
end
end
require 'spec_helper'
describe EventCreateService do
let(:service) { EventCreateService.new }
describe 'Issues' do
describe :open_issue do
let(:issue) { create(:issue) }
it { service.open_issue(issue, issue.author).should be_true }
it "should create new event" do
expect { service.open_issue(issue, issue.author) }.to change { Event.count }
end
end
describe :close_issue do
let(:issue) { create(:issue) }
it { service.close_issue(issue, issue.author).should be_true }
it "should create new event" do
expect { service.close_issue(issue, issue.author) }.to change { Event.count }
end
end
describe :reopen_issue do
let(:issue) { create(:issue) }
it { service.reopen_issue(issue, issue.author).should be_true }
it "should create new event" do
expect { service.reopen_issue(issue, issue.author) }.to change { Event.count }
end
end
end
describe 'Merge Requests' do
describe :open_mr do
let(:merge_request) { create(:merge_request) }
it { service.open_mr(merge_request, merge_request.author).should be_true }
it "should create new event" do
expect { service.open_mr(merge_request, merge_request.author) }.to change { Event.count }
end
end
describe :close_mr do
let(:merge_request) { create(:merge_request) }
it { service.close_mr(merge_request, merge_request.author).should be_true }
it "should create new event" do
expect { service.close_mr(merge_request, merge_request.author) }.to change { Event.count }
end
end
describe :merge_mr do
let(:merge_request) { create(:merge_request) }
it { service.merge_mr(merge_request, merge_request.author).should be_true }
it "should create new event" do
expect { service.merge_mr(merge_request, merge_request.author) }.to change { Event.count }
end
end
describe :reopen_mr do
let(:merge_request) { create(:merge_request) }
it { service.reopen_mr(merge_request, merge_request.author).should be_true }
it "should create new event" do
expect { service.reopen_mr(merge_request, merge_request.author) }.to change { Event.count }
end
end
end
describe 'Milestone' do
let(:user) { create :user }
describe :open_milestone do
let(:milestone) { create(:milestone) }
it { service.open_milestone(milestone, user).should be_true }
it "should create new event" do
expect { service.open_milestone(milestone, user) }.to change { Event.count }
end
end
describe :close_mr do
let(:milestone) { create(:milestone) }
it { service.close_milestone(milestone, user).should be_true }
it "should create new event" do
expect { service.close_milestone(milestone, user) }.to change { Event.count }
end
end
end
end
......@@ -90,7 +90,7 @@ def setup_stubs()
size: 12.45
)
ActivityObserver.any_instance.stub(
BaseObserver.any_instance.stub(
current_user: double("current_user", id: 1)
)
end
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment