Commit a97a4905 authored by Bob Van Landuyt's avatar Bob Van Landuyt Committed by Kushal Pandya

Use a serializer to represent Analytics for groups

parent e50d7588
class Groups::AnalyticsController < Groups::ApplicationController
before_action :group
before_action :check_contribution_analytics_available!
before_action :load_events
layout 'group'
def show
@users = @group.users.select(:id, :name, :username).reorder(:id)
@start_date = params[:start_date] || Date.today - 1.week
@events = Event.contributions
.where("created_at > ?", @start_date)
.where(project_id: @group.projects)
@stats = {}
@stats[:total_events] = count_by_user(@events.totals_by_author)
@stats[:push] = count_by_user(@events.code_push.totals_by_author)
@stats[:merge_requests_created] = count_by_user(@events.merge_requests.created.totals_by_author)
@stats[:merge_requests_merged] = count_by_user(@events.merge_requests.merged.totals_by_author)
@stats[:issues_created] = count_by_user(@events.issues.created.totals_by_author)
@stats[:issues_closed] = count_by_user(@events.issues.closed.totals_by_author)
respond_to do |format|
format.html do
@stats = {}
@stats[:push] = count_by_user(event_totals[:push])
@stats[:merge_requests_created] = count_by_user(event_totals[:merge_requests_created])
@stats[:issues_closed] = count_by_user(event_totals[:issues_closed])
end
format.json do
render json: GroupAnalyticsSerializer
.new(events: event_totals)
.represent(users), status: 200
end
end
end
private
def count_by_user(data)
user_ids.map { |id| data.fetch(id, 0) }
users.map { |user| data.fetch(user.id, 0) }
end
def users
@users ||= @group.users.select(:id, :name, :username).reorder(:id)
end
def load_events
@start_date = params[:start_date] || Date.today - 1.week
@events = Event.contributions
.where("created_at > ?", @start_date)
.where(project_id: @group.projects)
end
def user_ids
@user_ids ||= @users.map(&:id)
def event_totals
@event_totals ||= {
push: @events.code_push.totals_by_author,
issues_created: @events.issues.created.totals_by_author,
issues_closed: @events.issues.closed.totals_by_author,
merge_requests_created: @events.merge_requests.created.totals_by_author,
merge_requests_merged: @events.merge_requests.merged.totals_by_author,
total_events: @events.totals_by_author
}
end
def check_contribution_analytics_available!
......
class GroupAnalyticsSerializer < BaseSerializer
entity UserAnalyticsEntity
end
class UserAnalyticsEntity < Grape::Entity
include RequestAwareEntity
EVENT_TYPES = [:push, :issues_created, :issues_closed, :merge_requests_created,
:merge_requests_merged, :total_events].freeze
expose :username
expose :name, as: :fullname
expose :user_web_url do |user|
user_path(user)
end
EVENT_TYPES.each do |event_type|
expose event_type do |user|
request.events[event_type].fetch(user.id, 0)
end
end
end
......@@ -72,13 +72,41 @@ describe Groups::AnalyticsController do
stats = assigns[:stats]
# NOTE: The array ordering matters! The view references them all by index
expect(stats[:total_events]).to eq([2, 2, 2])
expect(stats[:merge_requests_merged]).to eq([0, 0, 0])
expect(stats[:merge_requests_created]).to eq([0, 1, 1])
expect(stats[:issues_closed]).to eq([1, 1, 0])
expect(stats[:push]).to eq([1, 0, 1])
end
it "returns member contributions JSON when format is JSON" do
get :show, group_id: group.path, format: :json
expect(json_response.length).to eq(3)
first_user = json_response.at(0)
expect(first_user["username"]).to eq(user.username)
expect(first_user["user_web_url"]).to eq("/#{user.username}")
expect(first_user["fullname"]).to eq(user.name)
expect(first_user["push"]).to eq(1)
expect(first_user["issues_created"]).to eq(0)
expect(first_user["issues_closed"]).to eq(1)
expect(first_user["merge_requests_created"]).to eq(0)
expect(first_user["merge_requests_merged"]).to eq(0)
expect(first_user["total_events"]).to eq(2)
end
it 'does not cause N+1 queries when the format is JSON' do
control_count = ActiveRecord::QueryRecorder.new do
get :show, group_id: group.path, format: :json
end
controller.instance_variable_set(:@group, nil)
user4 = create(:user)
group.add_user(user4, GroupMember::DEVELOPER)
expect { get :show, group_id: group.path, format: :json }
.not_to exceed_query_limit(control_count)
end
describe 'with views' do
render_views
......
require 'spec_helper'
describe UserAnalyticsEntity do
let(:user) { build_stubbed(:user) }
let(:events) do
{
push: {},
issues_created: {},
issues_closed: {},
merge_requests_created: {},
merge_requests_merged: {},
total_events: {}
}
end
let(:request) { double('request') }
subject(:json) { described_class.new(user, request: request).as_json }
before do
allow(request).to receive(:events).and_return(events)
end
it 'has all the user attributes' do
is_expected.to include(:username, :fullname, :user_web_url)
end
[:push, :issues_created, :issues_closed, :merge_requests_created,
:merge_requests_merged, :total_events].each do |event_type|
it "fetches #{event_type} events for the user from the request" do
events[event_type] = { user.id => 42 }
expect(json[event_type]).to eq(42)
end
end
it 'sets 0 as the total when there were no events for a type' do
expect(json[:total_events]).to eq(0)
end
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