Commit 9668e8b9 authored by Tan Le's avatar Tan Le Committed by Bob Van Landuyt

Extract sorting logic to model

This concern should belong to the model. It is also consistent with
patterns across other models (e.g. Issues, MergeRequests)
parent daa3d9cc
...@@ -13,11 +13,18 @@ class AuditEvent < ApplicationRecord ...@@ -13,11 +13,18 @@ class AuditEvent < ApplicationRecord
scope :by_entity_type, -> (entity_type) { where(entity_type: entity_type) } scope :by_entity_type, -> (entity_type) { where(entity_type: entity_type) }
scope :by_entity_id, -> (entity_id) { where(entity_id: entity_id) } scope :by_entity_id, -> (entity_id) { where(entity_id: entity_id) }
scope :order_by_id_desc, -> { order(id: :desc) }
scope :order_by_id_asc, -> { order(id: :asc) }
after_initialize :initialize_details after_initialize :initialize_details
def self.order_by(method)
case method.to_s
when 'created_asc'
order(id: :asc)
else
order(id: :desc)
end
end
def initialize_details def initialize_details
self.details = {} if details.nil? self.details = {} if details.nil?
end end
......
...@@ -2,20 +2,33 @@ ...@@ -2,20 +2,33 @@
class AuditLogFinder class AuditLogFinder
include CreatedAtFilter include CreatedAtFilter
include FinderMethods
VALID_ENTITY_TYPES = %w[Project User Group].freeze VALID_ENTITY_TYPES = %w[Project User Group].freeze
def initialize(params) # Instantiates a new finder
#
# @param [Hash] params
# @option params [String] :entity_type
# @option params [Integer] :entity_id
# @option params [DateTime] :created_after from created_at date
# @option params [DateTime] :created_before to created_at date
# @option params [String] :sort order by field_direction (e.g. created_asc)
#
# @return [AuditLogFinder]
def initialize(params = {})
@params = params @params = params
end end
# Filters and sorts records according to `params`
#
# @return [AuditEvent::ActiveRecord_Relation]
def execute def execute
audit_events = AuditEvent.all audit_events = AuditEvent.all
audit_events = by_entity(audit_events) audit_events = by_entity(audit_events)
audit_events = by_created_at(audit_events) audit_events = by_created_at(audit_events)
audit_events = sort(audit_events)
audit_events = by_id(audit_events)
audit_events sort(audit_events)
end end
private private
...@@ -27,26 +40,22 @@ class AuditLogFinder ...@@ -27,26 +40,22 @@ class AuditLogFinder
audit_events = audit_events.by_entity_type(params[:entity_type]) audit_events = audit_events.by_entity_type(params[:entity_type])
if params[:entity_id].present? && params[:entity_id] != '0' if valid_entity_id?
audit_events = audit_events.by_entity_id(params[:entity_id]) audit_events = audit_events.by_entity_id(params[:entity_id])
end end
audit_events audit_events
end end
def by_id(audit_events)
return audit_events unless params[:id].present?
audit_events.find_by_id(params[:id])
end
def sort(audit_events) def sort(audit_events)
return audit_events.order_by_id_asc if params[:sort] == 'created_asc' audit_events.order_by(params[:sort])
audit_events.order_by_id_desc
end end
def valid_entity_type? def valid_entity_type?
VALID_ENTITY_TYPES.include? params[:entity_type] VALID_ENTITY_TYPES.include? params[:entity_type]
end end
def valid_entity_id?
params[:entity_id].to_i.nonzero?
end
end end
...@@ -37,8 +37,10 @@ module API ...@@ -37,8 +37,10 @@ module API
requires :id, type: Integer, desc: 'The ID of audit event' requires :id, type: Integer, desc: 'The ID of audit event'
end end
get ':id' do get ':id' do
audit_event = AuditEvent.find_by_id(params[:id]) # rubocop: disable CodeReuse/ActiveRecord
not_found!('Audit Event') unless audit_event # This is not `find_by!` from ActiveRecord
audit_event = AuditLogFinder.new.find_by!(id: params[:id])
# rubocop: enable CodeReuse/ActiveRecord
present audit_event, with: EE::API::Entities::AuditEvent present audit_event, with: EE::API::Entities::AuditEvent
end end
......
...@@ -114,10 +114,11 @@ module EE ...@@ -114,10 +114,11 @@ module EE
requires :audit_event_id, type: Integer, desc: 'The ID of the audit event' requires :audit_event_id, type: Integer, desc: 'The ID of the audit event'
end end
get '/:audit_event_id' do get '/:audit_event_id' do
audit_log_finder_params = audit_log_finder_params(user_group) # rubocop: disable CodeReuse/ActiveRecord
audit_event = AuditLogFinder.new(audit_log_finder_params.merge(id: params[:audit_event_id])).execute # This is not `find_by!` from ActiveRecord
audit_event = AuditLogFinder.new(audit_log_finder_params(user_group))
not_found!('Audit Event') unless audit_event .find_by!(id: params[:audit_event_id])
# rubocop: enable CodeReuse/ActiveRecord
present audit_event, with: EE::API::Entities::AuditEvent present audit_event, with: EE::API::Entities::AuditEvent
end end
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
require 'spec_helper' require 'spec_helper'
describe AuditLogFinder do describe AuditLogFinder do
describe '#execute' do
let_it_be(:user_audit_event) { create(:user_audit_event, created_at: 3.days.ago) } let_it_be(:user_audit_event) { create(:user_audit_event, created_at: 3.days.ago) }
let_it_be(:project_audit_event) { create(:project_audit_event, created_at: 2.days.ago) } let_it_be(:project_audit_event) { create(:project_audit_event, created_at: 2.days.ago) }
let_it_be(:group_audit_event) { create(:group_audit_event, created_at: 1.day.ago) } let_it_be(:group_audit_event) { create(:group_audit_event, created_at: 1.day.ago) }
describe '#execute' do
subject { described_class.new(params).execute } subject { described_class.new(params).execute }
context 'no filtering' do context 'no filtering' do
...@@ -27,6 +27,14 @@ describe AuditLogFinder do ...@@ -27,6 +27,14 @@ describe AuditLogFinder do
end end
end end
context 'invalid entity_id' do
let(:params) { { entity_type: 'User', entity_id: '0' } }
it 'ignores entity_id and returns all events for given entity_type' do
expect(subject.count).to eq(1)
end
end
shared_examples 'finds the right event' do shared_examples 'finds the right event' do
it 'finds the right event' do it 'finds the right event' do
expect(subject.count).to eq(1) expect(subject.count).to eq(1)
...@@ -137,22 +145,21 @@ describe AuditLogFinder do ...@@ -137,22 +145,21 @@ describe AuditLogFinder do
end end
end end
end end
end
context 'filtering by id' do describe '#find_by!' do
context 'non-existent id provided' do let(:params) { {} }
let(:params) { { id: 'non-existent-id' } } let(:id) { user_audit_event.id }
it 'returns nil' do subject { described_class.new(params).find_by!(id: id) }
expect(subject).to be_nil
end
end
context 'existent id provided' do it { is_expected.to eq(user_audit_event) }
let(:params) { { id: user_audit_event.id } }
it 'returns the specific audit events with the id' do context 'non-existent id provided' do
expect(subject).to eql(user_audit_event) let(:id) { 'non-existent-id' }
end
it 'raises exception' do
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
end end
end end
end end
......
...@@ -13,6 +13,30 @@ RSpec.describe AuditEvent, type: :model do ...@@ -13,6 +13,30 @@ RSpec.describe AuditEvent, type: :model do
it { is_expected.to validate_presence_of(:entity_type) } it { is_expected.to validate_presence_of(:entity_type) }
end end
describe '.order_by' do
let_it_be(:event_1) { create(:audit_event) }
let_it_be(:event_2) { create(:audit_event) }
let_it_be(:event_3) { create(:audit_event) }
subject(:event) { described_class.order_by(method) }
context 'when sort by created_at in ascending order' do
let(:method) { 'created_asc' }
it 'sorts results by id in ascending order' do
expect(event).to eq([event_1, event_2, event_3])
end
end
context 'when it is default' do
let(:method) { nil }
it 'sorts results by id in descending order' do
expect(event).to eq([event_3, event_2, event_1])
end
end
end
describe '#author_name' do describe '#author_name' do
context 'when user exists' do context 'when user exists' do
let(:user) { create(:user, name: 'John Doe') } let(:user) { create(:user, name: 'John Doe') }
......
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