#435: fetch data for BuildLists graph
This commit is contained in:
parent
71e7b3b37e
commit
af7f9c6a15
|
@ -1,7 +1,74 @@
|
||||||
class StatisticsController < ApplicationController
|
class StatisticsController < ApplicationController
|
||||||
|
|
||||||
|
RANGES = [
|
||||||
|
RANGE_TWENTY_FOUR_HOURS = 'twenty_four_hours',
|
||||||
|
RANGE_LAST_7_DAYS = 'last_7_days',
|
||||||
|
RANGE_LAST_30_DAYS = 'last_30_days',
|
||||||
|
RANGE_LAST_60_DAYS = 'last_60_days',
|
||||||
|
RANGE_LAST_90_DAYS = 'last_90_days',
|
||||||
|
RANGE_LAST_180_DAYS = 'last_180_days',
|
||||||
|
RANGE_LAST_YEAR = 'last_year',
|
||||||
|
RANGE_CUSTOM = 'custom',
|
||||||
|
]
|
||||||
|
|
||||||
|
before_filter :init_variables
|
||||||
|
|
||||||
def index
|
def index
|
||||||
# TODO
|
# TODO
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.json do
|
||||||
|
scope = Statistic.for_period(@range_start, @range_end)
|
||||||
|
@build_lists = scope.build_lists(@range_start, @range_end, @unit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def init_variables
|
||||||
|
case params[:range]
|
||||||
|
when RANGE_TWENTY_FOUR_HOURS
|
||||||
|
@range_end = Time.now.utc
|
||||||
|
@range_start = @range_end - 1.day
|
||||||
|
@unit = :hour
|
||||||
|
when RANGE_LAST_7_DAYS
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 7.days
|
||||||
|
@unit = :day
|
||||||
|
when RANGE_LAST_30_DAYS
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 30.days
|
||||||
|
@unit = :day
|
||||||
|
when RANGE_LAST_60_DAYS
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 30.days
|
||||||
|
@unit = :day
|
||||||
|
when RANGE_LAST_90_DAYS
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 90.days
|
||||||
|
@unit = :day
|
||||||
|
when RANGE_LAST_180_DAYS
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 180.days
|
||||||
|
@unit = :month
|
||||||
|
when RANGE_LAST_YEAR
|
||||||
|
@range_end = Date.today
|
||||||
|
@range_start = @range_end - 1.year
|
||||||
|
@unit = :month
|
||||||
|
when RANGE_CUSTOM
|
||||||
|
@range_start = Time.parse(params[:range_start]).utc
|
||||||
|
@range_end = Time.parse(params[:range_end]).utc
|
||||||
|
diff = @range_end - @range_start
|
||||||
|
@unit =
|
||||||
|
if diff <= 24.hours
|
||||||
|
:hour
|
||||||
|
elsif diff <= 90.days
|
||||||
|
:day
|
||||||
|
else
|
||||||
|
:month
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -1,18 +1,8 @@
|
||||||
module StatisticsHelper
|
module StatisticsHelper
|
||||||
RANGES = %w(
|
|
||||||
twenty_four_hours
|
|
||||||
last_7_days
|
|
||||||
last_30_days
|
|
||||||
last_60_days
|
|
||||||
last_90_days
|
|
||||||
last_180_days
|
|
||||||
last_year
|
|
||||||
custom
|
|
||||||
)
|
|
||||||
|
|
||||||
def statistics_range_options
|
def statistics_range_options
|
||||||
options_for_select(
|
options_for_select(
|
||||||
RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
|
StatisticsController::RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
class Statistic < ActiveRecord::Base
|
class Statistic < ActiveRecord::Base
|
||||||
# TYPES = %w()
|
|
||||||
|
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
|
|
||||||
validates :user_id,
|
validates :user_id,
|
||||||
uniqueness: { scope: [:project_id, :type, :activity_at] },
|
uniqueness: { scope: [:project_id, :key, :activity_at] },
|
||||||
presence: true
|
presence: true
|
||||||
|
|
||||||
validates :email,
|
validates :email,
|
||||||
|
@ -17,7 +15,7 @@ class Statistic < ActiveRecord::Base
|
||||||
validates :project_name_with_owner,
|
validates :project_name_with_owner,
|
||||||
presence: true
|
presence: true
|
||||||
|
|
||||||
validates :type,
|
validates :key,
|
||||||
presence: true
|
presence: true
|
||||||
|
|
||||||
validates :counter,
|
validates :counter,
|
||||||
|
@ -30,30 +28,93 @@ class Statistic < ActiveRecord::Base
|
||||||
:email,
|
:email,
|
||||||
:project_id,
|
:project_id,
|
||||||
:project_name_with_owner,
|
:project_name_with_owner,
|
||||||
:type,
|
:key,
|
||||||
:counter,
|
:counter,
|
||||||
:activity_at
|
:activity_at
|
||||||
|
|
||||||
def self.now_statsd_increment(options = {})
|
scope :for_period, -> (start_date, end_date) { where(activity_at: (start_date..end_date)) }
|
||||||
|
|
||||||
|
def self.build_lists(range_start, range_end, unit)
|
||||||
|
items = select("SUM(counter) as count, date_trunc('#{ unit }', activity_at) as activity_at").
|
||||||
|
group("date_trunc('#{ unit }', activity_at)").order('activity_at')
|
||||||
|
|
||||||
|
|
||||||
|
build_started = items.where(key: "build_list.#{BuildList::BUILD_STARTED}")
|
||||||
|
success = items.where(key: "build_list.#{BuildList::SUCCESS}")
|
||||||
|
build_error = items.where(key: "build_list.#{BuildList::BUILD_ERROR}")
|
||||||
|
build_published = items.where(key: "build_list.#{BuildList::BUILD_PUBLISHED}")
|
||||||
|
|
||||||
|
{
|
||||||
|
build_started: prepare_collection(build_started, range_start, range_end, unit),
|
||||||
|
success: prepare_collection(success, range_start, range_end, unit),
|
||||||
|
build_error: prepare_collection(build_error, range_start, range_end, unit),
|
||||||
|
build_published: prepare_collection(build_published, range_start, range_end, unit),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prepare_collection(items, range_start, range_end, unit)
|
||||||
|
format = unit == :hour ? '%F %H:00:00' : '%F'
|
||||||
|
items = items.map do |item|
|
||||||
|
{ x: item.activity_at.strftime(format), y: item.count }
|
||||||
|
end
|
||||||
|
if items.size == 0
|
||||||
|
start = range_start
|
||||||
|
while start <= range_end
|
||||||
|
items.unshift({ x: start.strftime(format), y: 0 })
|
||||||
|
start += 1.send(unit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if items[0].try(:[], :x) != range_start.strftime(format)
|
||||||
|
items.unshift({ x: range_start.strftime(format), y: 0 })
|
||||||
|
end
|
||||||
|
if items[-1].try(:[], :x) != range_end.strftime(format)
|
||||||
|
items << { x: range_end.strftime(format), y: 0 }
|
||||||
|
end
|
||||||
|
items
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def format
|
||||||
|
@format ||= case period.unit
|
||||||
|
when 'hour'
|
||||||
|
'%F %H:00:00'
|
||||||
|
else # 'day', 'month'
|
||||||
|
'%F'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.now_statsd_increment(activity_at: nil, user_id: nil, project_id: nil, key: nil)
|
||||||
# Truncates a DateTime to the minute
|
# Truncates a DateTime to the minute
|
||||||
activity_at = options[:activity_at].utc.change(min: 0)
|
activity_at = activity_at.utc.change(min: 0)
|
||||||
user = User.find options[:user_id]
|
user = User.find user_id
|
||||||
project = Project.find options[:project_id]
|
project = Project.find project_id
|
||||||
Statistic.create(
|
Statistic.create(
|
||||||
user: user,
|
user_id: user_id,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
project: project,
|
project_id: project_id,
|
||||||
project_name_with_owner: project.name_with_owner,
|
project_name_with_owner: project.name_with_owner,
|
||||||
type: options[:type],
|
key: key,
|
||||||
activity_at: activity_at
|
activity_at: activity_at
|
||||||
)
|
)
|
||||||
ensure
|
ensure
|
||||||
Statistic.where(
|
Statistic.where(
|
||||||
user_id: options[:user_id],
|
user_id: user_id,
|
||||||
project_id: options[:project_id],
|
project_id: project_id,
|
||||||
type: options[:type],
|
key: key,
|
||||||
activity_at: activity_at
|
activity_at: activity_at
|
||||||
).update_all('counter = counter + ?', options[:counter])
|
).update_all('counter = counter + 1')
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.fill_in
|
||||||
|
BuildList.find_each do |bl|
|
||||||
|
Statistic.now_statsd_increment({
|
||||||
|
activity_at: bl.updated_at,
|
||||||
|
key: "build_list.#{bl.status}",
|
||||||
|
project_id: bl.project_id,
|
||||||
|
user_id: bl.user_id,
|
||||||
|
})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.statsd_increment(options = {})
|
def self.statsd_increment(options = {})
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
= image_tag 'loading-large.gif'
|
= image_tag 'loading-large.gif'
|
||||||
.no-data{ ng_hide: 'loading || statistics.build_lists' }
|
.no-data{ ng_hide: 'loading || statistics.build_lists' }
|
||||||
= t('.no_data')
|
= t('.no_data')
|
||||||
%canvas#build_lists_chart ng-show='statistics.build_lists'
|
%canvas#build_lists_chart{ ng_show: 'statistics.build_lists' }
|
||||||
|
|
||||||
.span3
|
.span3
|
||||||
.panel-wrapper
|
.panel-wrapper
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
json.build_lists @build_lists
|
|
@ -15,6 +15,11 @@ en:
|
||||||
total_user_sessions: "Total user sessions"
|
total_user_sessions: "Total user sessions"
|
||||||
no_data: "No data available"
|
no_data: "No data available"
|
||||||
|
|
||||||
|
build_lists:
|
||||||
|
build_started_title: "Build started"
|
||||||
|
success_title: "Build complete"
|
||||||
|
build_error_title: "Build error"
|
||||||
|
build_published_title: "Build has been published"
|
||||||
|
|
||||||
helper:
|
helper:
|
||||||
period:
|
period:
|
||||||
|
|
|
@ -5,7 +5,7 @@ class CreateStatistics < ActiveRecord::Migration
|
||||||
t.string :email, null: false
|
t.string :email, null: false
|
||||||
t.integer :project_id, null: false
|
t.integer :project_id, null: false
|
||||||
t.string :project_name_with_owner, null: false
|
t.string :project_name_with_owner, null: false
|
||||||
t.string :type, null: false
|
t.string :key, null: false
|
||||||
t.integer :counter, null: false, default: 0
|
t.integer :counter, null: false, default: 0
|
||||||
t.datetime :activity_at, null: false
|
t.datetime :activity_at, null: false
|
||||||
|
|
||||||
|
@ -15,13 +15,13 @@ class CreateStatistics < ActiveRecord::Migration
|
||||||
|
|
||||||
add_index :statistics, :user_id
|
add_index :statistics, :user_id
|
||||||
add_index :statistics, :project_id
|
add_index :statistics, :project_id
|
||||||
add_index :statistics, :type
|
add_index :statistics, :key
|
||||||
add_index :statistics, [:user_id, :type, :activity_at]
|
add_index :statistics, [:user_id, :key, :activity_at]
|
||||||
add_index :statistics, [:project_id, :type, :activity_at]
|
add_index :statistics, [:project_id, :key, :activity_at]
|
||||||
add_index :statistics, [:type, :activity_at]
|
add_index :statistics, [:key, :activity_at]
|
||||||
add_index :statistics, :activity_at
|
add_index :statistics, :activity_at
|
||||||
|
|
||||||
add_index :statistics, [:user_id, :project_id, :type, :activity_at], unique: true,
|
add_index :statistics, [:user_id, :project_id, :key, :activity_at], unique: true,
|
||||||
name: 'index_statistics_on_all_keys'
|
name: 'index_statistics_on_all_keys'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
12
db/schema.rb
12
db/schema.rb
|
@ -586,18 +586,18 @@ ActiveRecord::Schema.define(version: 20141006182907) do
|
||||||
t.string "email", null: false
|
t.string "email", null: false
|
||||||
t.integer "project_id", null: false
|
t.integer "project_id", null: false
|
||||||
t.string "project_name_with_owner", null: false
|
t.string "project_name_with_owner", null: false
|
||||||
t.string "type", null: false
|
t.string "key", null: false
|
||||||
t.integer "counter", default: 0, null: false
|
t.integer "counter", default: 0, null: false
|
||||||
t.datetime "activity_at", null: false
|
t.datetime "activity_at", null: false
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.index ["activity_at"], :name => "index_statistics_on_activity_at"
|
t.index ["activity_at"], :name => "index_statistics_on_activity_at"
|
||||||
t.index ["project_id", "type", "activity_at"], :name => "index_statistics_on_project_id_and_type_and_activity_at"
|
t.index ["key", "activity_at"], :name => "index_statistics_on_key_and_activity_at"
|
||||||
|
t.index ["key"], :name => "index_statistics_on_key"
|
||||||
|
t.index ["project_id", "key", "activity_at"], :name => "index_statistics_on_project_id_and_key_and_activity_at"
|
||||||
t.index ["project_id"], :name => "index_statistics_on_project_id"
|
t.index ["project_id"], :name => "index_statistics_on_project_id"
|
||||||
t.index ["type", "activity_at"], :name => "index_statistics_on_type_and_activity_at"
|
t.index ["user_id", "key", "activity_at"], :name => "index_statistics_on_user_id_and_key_and_activity_at"
|
||||||
t.index ["type"], :name => "index_statistics_on_type"
|
t.index ["user_id", "project_id", "key", "activity_at"], :name => "index_statistics_on_all_keys", :unique => true
|
||||||
t.index ["user_id", "project_id", "type", "activity_at"], :name => "index_statistics_on_all_keys", :unique => true
|
|
||||||
t.index ["user_id", "type", "activity_at"], :name => "index_statistics_on_user_id_and_type_and_activity_at"
|
|
||||||
t.index ["user_id"], :name => "index_statistics_on_user_id"
|
t.index ["user_id"], :name => "index_statistics_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue