summaryrefslogtreecommitdiff
path: root/app/finders/events_finder.rb
blob: 9c56451fd44a54369d32be44a9d8f9cef286bb3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# frozen_string_literal: true

class EventsFinder
  prepend FinderMethods
  prepend FinderWithCrossProjectAccess

  MAX_PER_PAGE = 100

  attr_reader :source, :params, :current_user, :scope

  requires_cross_project_access unless: -> { source.is_a?(Project) }, model: Event

  # Used to filter Events
  #
  # Arguments:
  #   source - which user or project to looks for events on
  #   current_user - only return events for projects visible to this user
  #   scope - return all events across a user's projects
  #   params:
  #     action: string
  #     target_type: string
  #     before: datetime
  #     after: datetime
  #     per_page: integer (max. 100)
  #     page: integer
  #     with_associations: boolean
  #     sort: 'asc' or 'desc'
  def initialize(params = {})
    @source = params.delete(:source)
    @current_user = params.delete(:current_user)
    @scope = params.delete(:scope)
    @params = params
  end

  def execute
    events = get_events

    events = by_current_user_access(events)
    events = by_action(events)
    events = by_target_type(events)
    events = by_created_at_before(events)
    events = by_created_at_after(events)
    events = sort(events)

    events = events.with_associations if params[:with_associations]
    paginated_filtered_by_user_visibility(events)
  end

  private

  def get_events
    if current_user && scope == 'all'
      EventCollection.new(current_user.authorized_projects).all_project_events
    else
      # EventCollection is responsible for applying the feature flag
      apply_feature_flags(source.events)
    end
  end

  def apply_feature_flags(events)
    return events if ::Feature.enabled?(:wiki_events)

    events.not_wiki_page
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def by_current_user_access(events)
    events.merge(Project.public_or_visible_to_user(current_user))
      .joins(:project)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  # rubocop: disable CodeReuse/ActiveRecord
  def by_action(events)
    return events unless Event::ACTIONS[params[:action]]

    events.where(action: Event::ACTIONS[params[:action]])
  end
  # rubocop: enable CodeReuse/ActiveRecord

  # rubocop: disable CodeReuse/ActiveRecord
  def by_target_type(events)
    return events unless Event::TARGET_TYPES[params[:target_type]]

    events.where(target_type: Event::TARGET_TYPES[params[:target_type]].name)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  # rubocop: disable CodeReuse/ActiveRecord
  def by_created_at_before(events)
    return events unless params[:before]

    events.where('events.created_at < ?', params[:before].beginning_of_day)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  # rubocop: disable CodeReuse/ActiveRecord
  def by_created_at_after(events)
    return events unless params[:after]

    events.where('events.created_at > ?', params[:after].end_of_day)
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def sort(events)
    return events unless params[:sort]

    if params[:sort] == 'asc'
      events.order_id_asc
    else
      events.order_id_desc
    end
  end

  def paginated_filtered_by_user_visibility(events)
    limited_events = events.page(page).per(per_page)
    visible_events = limited_events.select { |event| event.visible_to_user?(current_user) }

    Kaminari.paginate_array(visible_events, total_count: events.count)
  end

  def per_page
    return MAX_PER_PAGE unless params[:per_page]

    [params[:per_page], MAX_PER_PAGE].min
  end

  def page
    params[:page] || 1
  end
end