BigW Consortium Gitlab

contributions_calendar.rb 2.83 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 27
      union = Gitlab::SQL::Union.new([repo_events, issue_events, mr_events])
      events = Event.find_by_sql(union.to_sql).map(&:attributes)
28

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

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

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

    def starting_year
45
      1.year.ago.year
46 47 48
    end

    def starting_month
49
      Date.today.month
50
    end
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

    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
76 77
  end
end