contributions_calendar.rb 3.0 KB
Newer Older
1 2
module Gitlab
  class ContributionsCalendar
3 4 5
    attr_reader :contributor
    attr_reader :current_user
    attr_reader :projects
6

7 8 9 10
    def initialize(contributor, current_user = nil)
      @contributor = contributor
      @current_user = current_user
      @projects = ContributedProjectsFinder.new(contributor).execute(current_user)
11 12
    end

13 14
    def activity_dates
      return @activity_dates if @activity_dates.present?
15

16 17
      # Can't use Event.contributions here because we need to check 3 different
      # project_features for the (currently) 3 different contribution types
18
      date_from = 1.year.ago
19 20 21 22 23 24
      repo_events = event_counts(date_from, :repository).
        having(action: Event::PUSHED)
      issue_events = event_counts(date_from, :issues).
        having(action: [Event::CREATED, Event::CLOSED], target_type: "Issue")
      mr_events = event_counts(date_from, :merge_requests).
        having(action: [Event::MERGED, Event::CREATED, Event::CLOSED], target_type: "MergeRequest")
25 26
      note_events = event_counts(date_from, :merge_requests).
        having(action: [Event::COMMENTED], target_type: "Note")
27

28
      union = Gitlab::SQL::Union.new([repo_events, issue_events, mr_events, note_events])
29
      events = Event.find_by_sql(union.to_sql).map(&:attributes)
30

31 32
      @activity_events = events.each_with_object(Hash.new {|h, k| h[k] = 0 }) do |event, activities|
        activities[event["date"]] += event["total_amount"]
33 34 35 36
      end
    end

    def events_by_date(date)
37 38
      events = Event.contributions.where(author_id: contributor.id).
        where(created_at: date.beginning_of_day..date.end_of_day).
39 40
        where(project_id: projects)

41 42
      # Use visible_to_user? instead of the complicated logic in activity_dates
      # because we're only viewing the events for a single day.
43
      events.select { |event| event.visible_to_user?(current_user) }
44 45 46
    end

    def starting_year
47
      1.year.ago.year
48 49 50
    end

    def starting_month
51
      Date.today.month
52
    end
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

    private

    def event_counts(date_from, feature)
      t = Event.arel_table

      # re-running the contributed projects query in each union is expensive, so
      # use IN(project_ids...) instead. It's the intersection of two users so
      # the list will be (relatively) short
      @contributed_project_ids ||= projects.uniq.pluck(:id)
      authed_projects = Project.where(id: @contributed_project_ids).
        with_feature_available_for_user(feature, current_user).
        reorder(nil).
        select(:id)

      conditions = t[:created_at].gteq(date_from.beginning_of_day).
        and(t[:created_at].lteq(Date.today.end_of_day)).
        and(t[:author_id].eq(contributor.id))

      Event.reorder(nil).
        select(t[:project_id], t[:target_type], t[:action], 'date(created_at) AS date', 'count(id) as total_amount').
        group(t[:project_id], t[:target_type], t[:action], 'date(created_at)').
        where(conditions).
        having(t[:project_id].in(Arel::Nodes::SqlLiteral.new(authed_projects.to_sql)))
    end
78 79
  end
end