Merge pull request #436 from abf/rosa-build:435-activity-statistics

#435: Activity statistics
This commit is contained in:
avokhmin 2014-10-14 21:50:27 +04:00
commit 5fb74d90bc
22 changed files with 4109 additions and 104 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,150 @@
RosaABF.controller 'StatisticsController', ['$scope', '$http', '$filter', ($scope, $http, $filter) ->
$scope.range = 'last_30_days'
$scope.range_start = $('#range_start').attr('value')
$scope.range_end = $('#range_end').attr('value')
$scope.loading = true
$scope.statistics = {}
$scope.statistics_path = '/statistics'
$scope.colors = [
'56, 132, 158',
'77, 169, 68',
'241, 128, 73',
'174, 199, 232',
'255, 187, 120',
'152, 223, 138',
'214, 39, 40',
'31, 119, 180'
]
$scope.charts = {}
$scope.init = ->
$('#range-form .date_picker').datepicker
'dateFormat': 'yy-mm-dd'
maxDate: 0
minDate: -366
showButtonPanel: true
$scope.rangeChange()
true
$scope.prepareRange = ->
range_start = new Date($scope.range_start)
range_end = new Date($scope.range_end)
if range_start > range_end
tmp = $scope.range_start
$scope.range_start = $scope.range_end
$scope.range_end = tmp
$scope.rangeChange = ->
$scope.loading = true
$scope.statistics = {}
$scope.prepareRange()
$('.doughnut-legend').remove()
params =
range: $scope.range
range_start: $scope.range_start
range_end: $scope.range_end
format: 'json'
$http.get($scope.statistics_path, params: params).success (results) ->
$scope.statistics = results
$scope.loading = false
# BuildLists
if $scope.statistics.build_lists
$scope.initBuildListsChart()
# PullRequests
if $scope.statistics.pull_requests
$scope.initPullRequestsChart()
# Issues
if $scope.statistics.issues
$scope.initIssuesChart()
.error (data, status, headers, config) ->
console.log 'error:'
$scope.loading = false
$scope.dateChart = (id, collections) ->
new_collections = $.grep collections, ( c ) ->
return c
if collections.length == new_collections.length
$scope.charts[id].destroy() if $scope.charts[id]
points = collections[0]
factor = points.length // 45 + 1
tooltipTitles = []
labels = _.map points, (d, index) ->
x = d.x
format =
if $scope.statistics.unit == 'hour'
# input date should have format: 'yyyy-MM-ddTHH:mm:ssZ'
x = x.replace(/\s/, 'T') + 'Z'
'HH:mm'
else
'yyyy-MM-dd'
x = $filter('date')(x, format)
tooltipTitles.push x
if index %% factor == 0
x
else
''
datasets = _.map collections, (collection, index) ->
data = _.map collection, (d) ->
d.y
dataset =
fillColor: "rgba(#{ $scope.colors[index] }, 0.5)"
strokeColor: "rgba(#{ $scope.colors[index] }, 1)"
pointColor: "rgba(#{ $scope.colors[index] }, 1)"
pointStrokeColor: "#fff"
data: data
data =
datasets: datasets
# We display only limited count of labels on X axis, but tooltips should have titles
# See: Chart.js "Added by avokhmin"
labels: labels
tooltipTitles: tooltipTitles
options =
responsive: true
context = $(id)[0].getContext('2d')
$scope.charts[id] = new Chart(context).Line(data, options)
$scope.initBuildListsChart = ->
$scope.dateChart '#build_lists_chart', [
$scope.statistics.build_lists.build_started,
$scope.statistics.build_lists.success,
$scope.statistics.build_lists.build_error,
$scope.statistics.build_lists.build_published
]
$scope.initPullRequestsChart = ->
$scope.dateChart '#pull_requests_chart', [
$scope.statistics.pull_requests.open,
$scope.statistics.pull_requests.closed,
$scope.statistics.pull_requests.approved
]
$scope.initIssuesChart = ->
$scope.dateChart '#issues_chart', [
$scope.statistics.issues.open,
$scope.statistics.issues.closed,
$scope.statistics.issues.approved
]
]

3383
app/assets/javascripts/lib/Chart.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,3 +6,4 @@
@import "design/custom";
@import "design/build_lists_monitoring";
@import "design/profile";
@import "design/statistics";

View File

@ -0,0 +1,14 @@
#manage-statistics {
.graph-key-color1 { background-color: #38849e; }
.graph-key-color2 { background-color: #4da944; }
.graph-key-color3 { background-color: #f18049; }
.graph-key-color4 { background-color: #aec7e8; }
.graph-key-color5 { background-color: #ffbb78; }
.graph-wrapper h3 span {
display: inline-block;
width: 10px;
height: 10px;
margin-left: 15px;
}
}

View File

@ -1,6 +1,8 @@
class ApplicationController < ActionController::Base
AIRBRAKE_IGNORE = [ActionController::InvalidAuthenticityToken,
AbstractController::ActionNotFound]
AIRBRAKE_IGNORE = [
ActionController::InvalidAuthenticityToken,
AbstractController::ActionNotFound
]
protect_from_forgery

View File

@ -0,0 +1,75 @@
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',
]
def index
respond_to do |format|
format.html
format.json do
init_variables
render json: StatisticPresenter.new(range_start: @range_start, range_end: @range_end, unit: @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
else
raise ActiveRecord::RecordNotFound
end
rescue ArgumentError
raise ActiveRecord::RecordNotFound
end
end

View File

@ -0,0 +1,9 @@
module StatisticsHelper
def statistics_range_options
options_for_select(
StatisticsController::RANGES.map { |r| [I18n.t(r, scope: 'statistics.helper.period'), r] }
)
end
end

View File

@ -3,10 +3,20 @@ module BuildListObserver
included do
before_update :update_average_build_time
before_update :update_statistic
end
private
def update_statistic
Statistic.statsd_increment(
activity_at: Time.now,
key: "build_list.#{status}",
project_id: project_id,
user_id: user_id,
) if status_changed?
end
def update_average_build_time
if status_changed?
self.started_at = Time.now if status == self.class::BUILD_STARTED

88
app/models/statistic.rb Normal file
View File

@ -0,0 +1,88 @@
class Statistic < ActiveRecord::Base
belongs_to :user
belongs_to :project
validates :user_id,
uniqueness: { scope: [:project_id, :key, :activity_at] },
presence: true
validates :email,
presence: true
validates :project_id,
presence: true
validates :project_name_with_owner,
presence: true
validates :key,
presence: true
validates :counter,
presence: true
validates :activity_at,
presence: true
attr_accessible :user_id,
:email,
:project_id,
:project_name_with_owner,
:key,
:counter,
:activity_at
scope :for_period, -> (start_date, end_date) { where(activity_at: (start_date..end_date)) }
scope :build_lists_started, -> { where(key: "build_list.#{BuildList::BUILD_STARTED}") }
scope :build_lists_success, -> { where(key: "build_list.#{BuildList::SUCCESS}") }
scope :build_lists_error, -> { where(key: "build_list.#{BuildList::BUILD_ERROR}") }
scope :build_lists_published, -> { where(key: "build_list.#{BuildList::BUILD_PUBLISHED}") }
def self.now_statsd_increment(activity_at: nil, user_id: nil, project_id: nil, key: nil)
# Truncates a DateTime to the minute
activity_at = activity_at.utc.change(min: 0)
user = User.find user_id
project = Project.find project_id
Statistic.create(
user_id: user_id,
email: user.email,
project_id: project_id,
project_name_with_owner: project.name_with_owner,
key: key,
activity_at: activity_at
)
ensure
Statistic.where(
user_id: user_id,
project_id: project_id,
key: key,
activity_at: activity_at
).update_all('counter = counter + 1')
end
# TODO: remove later
def self.fill_in_build_lists
BuildList.find_each do |bl|
Statistic.now_statsd_increment({
activity_at: bl.created_at,
key: "build_list.#{BuildList::BUILD_STARTED}",
project_id: bl.project_id,
user_id: bl.user_id,
})
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
def self.statsd_increment(options = {})
Statistic.perform_later(:middle, :now_statsd_increment, options)
end
end

View File

@ -0,0 +1,72 @@
class StatisticPresenter < ApplicationPresenter
attr_accessor :range_start, :range_end, :unit
def initialize(range_start: nil, range_end: nil, unit: nil)
@range_start = range_start
@range_end = range_end
@unit = unit
end
def as_json(options = nil)
{
build_lists: {
build_started: prepare_collection(build_lists_started),
success: prepare_collection(build_lists_success),
build_error: prepare_collection(build_lists_error),
build_published: prepare_collection(build_lists_published),
build_started_count: build_lists_started.sum(&:count),
success_count: build_lists_success.sum(&:count),
build_error_count: build_lists_error.sum(&:count),
build_published_count: build_lists_published.sum(&:count),
}
}
end
private
def scope
@scope ||= Statistic.for_period(range_start, range_end)
end
def build_lists
@build_lists ||= scope.
select("SUM(counter) as count, date_trunc('#{ unit }', activity_at) as activity_at").
group("date_trunc('#{ unit }', activity_at)").order('activity_at')
end
def build_lists_started
@build_lists_started ||= build_lists.build_lists_started.to_a
end
def build_lists_success
@build_lists_success ||= build_lists.build_lists_success.to_a
end
def build_lists_error
@build_lists_error ||= build_lists.build_lists_error.to_a
end
def build_lists_published
@build_lists_published ||= build_lists.build_lists_published.to_a
end
def prepare_collection(items)
data = []
to = range_start
while to <= range_end
from = to - 1.send(unit)
y = items.find{ |i| i.activity_at > from && i.activity_at <= to }.try(:count)
data << { x: from.strftime(format), y: y || 0 }
to += 1.send(unit)
end
data
end
def format
@format ||= unit == :hour ? '%F %H:00:00' : '%F'
end
end

View File

@ -0,0 +1,55 @@
.row
.span8
.graph-wrapper
%h3
%span.graph-key-color1
= t('.build_started_title')
%span.graph-key-color2
= t('.success_title')
%span.graph-key-color3
= t('.build_error_title')
%span.graph-key-color4
= t('.build_published_title')
.centered.graph-loading{ ng_show: 'loading' }
= image_tag 'loading-large.gif'
.no-data{ ng_hide: 'loading || statistics.build_lists' }
= t('.no_data')
%canvas#build_lists_chart{ ng_show: 'statistics.build_lists' }
.span3
.panel-wrapper
%h3
= t('.total_build_started')
.panel-data
= image_tag 'loading-small.gif', ng_show: 'loading'
.no-data{ ng_hide: 'loading || statistics.build_lists.build_started_count >= 0' }
= t('.no_data')
{{ statistics.build_lists.build_started_count | number }}
.panel-wrapper
%h3
= t('.total_success')
.panel-data
= image_tag 'loading-small.gif', ng_show: 'loading'
.no-data{ ng_hide: 'loading || statistics.build_lists.success_count >= 0' }
= t('.no_data')
{{ statistics.build_lists.success_count | number }}
.panel-wrapper
%h3
= t('.total_build_error')
.panel-data
= image_tag 'loading-small.gif', ng_show: 'loading'
.no-data{ ng_hide: 'loading || statistics.build_lists.build_error_count >= 0' }
= t('.no_data')
{{ statistics.build_lists.build_error_count | number }}
.panel-wrapper
%h3
= t('.total_build_published')
.panel-data
= image_tag 'loading-small.gif', ng_show: 'loading'
.no-data{ ng_hide: 'loading || statistics.build_lists.build_published_count >= 0' }
= t('.no_data')
{{ statistics.build_lists.build_published_count | number }}

View File

@ -0,0 +1,14 @@
.row
.span11.flash_notify
%h3.text-info
= t('.header')
= form_tag '#', class: 'form-inline alert alert-info centered', id: 'range-form' do
%label.control-label
= t('.range_label')
= select_tag 'range', statistics_range_options, id: 'range_select', class: 'select input-medium', ng_model: 'range', ng_change: 'rangeChange()'
%span{ ng_show: "range == 'custom'" }
= text_field_tag :range_start, Date.today - 1.month, class: 'date_picker input-medium', placeholder: t('.range_start_placeholder'), ng_model: 'range_start', ng_change: 'rangeChange()', readonly: true
= t('.range_separator')
= text_field_tag :range_end, Date.today, class: 'date_picker input-medium', placeholder: t('.range_end_placeholder'), ng_model: 'range_end', ng_change: 'rangeChange()', readonly: true

View File

@ -0,0 +1,7 @@
- set_meta_tags title: t('.header')
#manage-statistics{ ng_controller: 'StatisticsController', ng_init: 'init()' }
= render 'filter'
= render 'build_lists'

View File

@ -9,6 +9,7 @@ en:
build_lists: Task monitoring
groups: Groups
advisories: Advisories
statistics: Statistics
bottom_menu:
copyright: ROSA Lab © %{year}
about: About the company

View File

@ -9,6 +9,7 @@ ru:
build_lists: Мониторинг задач
groups: Группы
advisories: Бюллетени
statistics: Статистика
bottom_menu:
copyright: ROSA Лаб. © %{year}
about: О компании
@ -47,7 +48,7 @@ ru:
wiki: Вики
platform_menu:
settings: Настройки
admins_menu_header: Центр управления
admins_menu_header: ЦУ
admins_menu:
users: Пользователи
register_requests: Инвайты

View File

@ -0,0 +1,34 @@
en:
statistics:
index:
header: "Statistics"
filter:
header: "Statistics"
range_label: "Display data for"
range_start_placeholder: "Select a start date"
range_separator: " and "
range_end_placeholder: "Select an end date"
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"
total_build_started: "Total build started"
total_success: "Total build complete"
total_build_error: "Total build error"
total_build_published: "Total build has been published"
helper:
period:
twenty_four_hours: "the last 24 hours"
last_7_days: "the last 7 days"
last_30_days: "the last 30 days"
last_60_days: "the last 60 days"
last_90_days: "the last 90 days"
last_180_days: "the last 6 months"
last_year: "the last year"
custom: "custom"

View File

@ -0,0 +1,34 @@
ru:
statistics:
index:
header: "Статистика"
filter:
header: "Статистика"
range_label: "Показать данные за"
range_start_placeholder: "Выберите начальную дату"
range_separator: " и "
range_end_placeholder: "Выберите конечную дату"
no_data: "Нет данных"
build_lists:
build_started_title: "Cобирается"
success_title: "Cобрано"
build_error_title: "Ошибка сборки"
build_published_title: "Опубликовано"
total_build_started: "Всего собирается"
total_success: "Всего собрано"
total_build_error: "Всего ошибок сборки"
total_build_published: "Всего опубликовано"
helper:
period:
twenty_four_hours: "последние 24 часа"
last_7_days: "последние 7 дней"
last_30_days: "последние 30 дней"
last_60_days: "последние 60 дней"
last_90_days: "последние 90 дней"
last_180_days: "последние 6 месяцев"
last_year: "последний год"
custom: "интервал"

View File

@ -13,6 +13,7 @@ Rosa::Application.routes.draw do
match '/sitemap.xml.gz' => 'sitemap#show', via: [:get, :post, :head], as: :sitemap
match '/robots.txt' => 'sitemap#robots', via: [:get, :post, :head], as: :robots
resources :statistics, only: [:index]
resource :contact, only: [:new, :create, :sended] do
get '/' => 'contacts#new'
get :sended

View File

@ -0,0 +1,32 @@
class CreateStatistics < ActiveRecord::Migration
def up
create_table :statistics do |t|
t.integer :user_id, null: false
t.string :email, null: false
t.integer :project_id, null: false
t.string :project_name_with_owner, null: false
t.string :key, null: false
t.integer :counter, null: false, default: 0
t.datetime :activity_at, null: false
t.timestamps
end
add_index :statistics, :user_id
add_index :statistics, :project_id
add_index :statistics, :key
add_index :statistics, [:user_id, :key, :activity_at]
add_index :statistics, [:project_id, :key, :activity_at]
add_index :statistics, [:key, :activity_at]
add_index :statistics, :activity_at
add_index :statistics, [:user_id, :project_id, :key, :activity_at], unique: true,
name: 'index_statistics_on_all_keys'
end
def down
drop_table :statistics
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140924203530) do
ActiveRecord::Schema.define(version: 20141006182907) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -31,8 +31,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.text "description", default: ""
t.text "references", default: ""
t.text "update_type", default: ""
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["advisory_id"], :name => "index_advisories_on_advisory_id", :unique => true
t.index ["update_type"], :name => "index_advisories_on_update_type"
end
@ -90,8 +90,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "version"
t.string "release"
t.string "package_type"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "actual", default: false
t.string "sha1"
t.integer "epoch"
@ -151,6 +151,31 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.index ["project_id"], :name => "index_build_lists_on_project_id"
end
create_table "projects", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "owner_id"
t.string "owner_type"
t.string "visibility", default: "open"
t.text "description"
t.string "ancestry"
t.boolean "has_issues", default: true
t.string "srpm_file_name"
t.integer "srpm_file_size"
t.datetime "srpm_updated_at"
t.string "srpm_content_type"
t.boolean "has_wiki", default: false
t.string "default_branch", default: "master"
t.boolean "is_package", default: true, null: false
t.integer "maintainer_id"
t.boolean "publish_i686_into_x86_64", default: false
t.string "owner_uname", null: false
t.boolean "architecture_dependent", default: false, null: false
t.integer "autostart_status"
t.index ["name", "owner_id", "owner_type"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false
end
create_table "build_scripts", force: true do |t|
t.integer "project_id", null: false
t.string "treeish", null: false
@ -160,6 +185,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.datetime "created_at"
t.datetime "updated_at"
t.index ["project_id", "treeish"], :name => "index_build_scripts_on_project_id_and_treeish", :unique => true
t.index ["project_id"], :name => "fk__build_scripts_project_id"
t.foreign_key ["project_id"], "projects", ["id"], :on_update => :no_action, :on_delete => :no_action, :name => "fk_build_scripts_project_id"
end
create_table "comments", force: true do |t|
@ -195,8 +222,6 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.text "message"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["eventable_id", "eventable_type"], :name => "index_event_logs_on_eventable_id_and_eventable_type"
t.index ["user_id"], :name => "index_event_logs_on_user_id"
end
create_table "flash_notifies", force: true do |t|
@ -204,8 +229,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.text "body_en", null: false
t.string "status", null: false
t.boolean "published", default: true, null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "groups", force: true do |t|
@ -225,8 +250,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.text "data"
t.integer "project_id"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "issues", force: true do |t|
@ -251,8 +276,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "key_id", null: false
t.integer "user_id", null: false
t.integer "repository_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["repository_id"], :name => "index_key_pairs_on_repository_id", :unique => true
end
@ -261,16 +286,16 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.integer "user_id", null: false
t.string "key_id", null: false
t.text "public", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["repository_id"], :name => "index_key_pairs_backup_on_repository_id", :unique => true
end
create_table "labelings", force: true do |t|
t.integer "label_id", null: false
t.integer "issue_id"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["issue_id"], :name => "index_labelings_on_issue_id"
end
@ -278,16 +303,16 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "name", null: false
t.string "color", null: false
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id"], :name => "index_labels_on_project_id"
end
create_table "mass_builds", force: true do |t|
t.integer "build_for_platform_id", null: false
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "arch_names"
t.integer "user_id"
t.integer "build_lists_count", default: 0, null: false
@ -310,6 +335,46 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.integer "status", default: 2000, null: false
end
create_table "users", force: true do |t|
t.string "name"
t.string "email", default: "", null: false
t.string "encrypted_password", limit: 128, default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at"
t.datetime "updated_at"
t.text "ssh_key"
t.string "uname"
t.string "role"
t.string "language", default: "en"
t.integer "own_projects_count", default: 0, null: false
t.text "professional_experience"
t.string "site"
t.string "company"
t.string "location"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
t.integer "failed_attempts", default: 0
t.string "unlock_token"
t.datetime "locked_at"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "authentication_token"
t.integer "build_priority", default: 50
t.boolean "sound_notifications", default: true
t.boolean "hide_email", default: true, null: false
t.index ["authentication_token"], :name => "index_users_on_authentication_token"
t.index ["confirmation_token"], :name => "index_users_on_confirmation_token", :unique => true
t.index ["email"], :name => "index_users_on_email", :unique => true
t.index ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
t.index ["uname"], :name => "index_users_on_uname", :unique => true
t.index ["unlock_token"], :name => "index_users_on_unlock_token", :unique => true
end
create_table "node_instructions", force: true do |t|
t.integer "user_id", null: false
t.text "encrypted_instruction", null: false
@ -317,6 +382,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "status"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["user_id"], :name => "fk__node_instructions_user_id"
t.foreign_key ["user_id"], "users", ["id"], :on_update => :no_action, :on_delete => :no_action, :name => "fk_node_instructions_user_id"
end
create_table "platform_arch_settings", force: true do |t|
@ -324,8 +391,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.integer "arch_id", null: false
t.integer "time_living", null: false
t.boolean "default"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["platform_id", "arch_id"], :name => "index_platform_arch_settings_on_platform_id_and_arch_id", :unique => true
end
@ -340,7 +407,7 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "owner_type"
t.string "visibility", default: "open", null: false
t.string "platform_type", default: "main", null: false
t.string "distrib_type"
t.string "distrib_type", null: false
t.integer "status"
t.datetime "last_regenerated_at"
t.integer "last_regenerated_status"
@ -398,8 +465,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.integer "build_count", default: 0, null: false
t.integer "arch_id", null: false
t.integer "project_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["project_id", "arch_id"], :name => "index_project_statistics_on_project_id_and_arch_id", :unique => true
end
@ -409,8 +476,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "sha1"
t.string "tag_name"
t.integer "format_id"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "project_to_repositories", force: true do |t|
@ -422,31 +489,6 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.index ["repository_id", "project_id"], :name => "index_project_to_repositories_on_repository_id_and_project_id", :unique => true
end
create_table "projects", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "owner_id"
t.string "owner_type"
t.string "visibility", default: "open"
t.text "description"
t.string "ancestry"
t.boolean "has_issues", default: true
t.boolean "has_wiki", default: false
t.string "srpm_file_name"
t.string "srpm_content_type"
t.integer "srpm_file_size"
t.datetime "srpm_updated_at"
t.string "default_branch", default: "master"
t.boolean "is_package", default: true, null: false
t.integer "maintainer_id"
t.boolean "publish_i686_into_x86_64", default: false
t.string "owner_uname", null: false
t.boolean "architecture_dependent", default: false, null: false
t.integer "autostart_status"
t.index ["name", "owner_id", "owner_type"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false
end
create_table "pull_requests", force: true do |t|
t.integer "issue_id", null: false
t.integer "to_project_id", null: false
@ -455,9 +497,9 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "from_ref", null: false
t.string "from_project_owner_uname"
t.string "from_project_name"
t.index ["from_project_id"], :name => "index_pull_requests_on_from_project_id"
t.index ["from_project_id"], :name => "index_pull_requests_on_head_project_id"
t.index ["issue_id"], :name => "index_pull_requests_on_issue_id"
t.index ["to_project_id"], :name => "index_pull_requests_on_to_project_id"
t.index ["to_project_id"], :name => "index_pull_requests_on_base_project_id"
end
create_table "register_requests", force: true do |t|
@ -505,8 +547,8 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.integer "status", default: 0
t.datetime "last_regenerated_at"
t.integer "last_regenerated_status"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "last_regenerated_log_sha1"
t.index ["repository_id", "platform_id"], :name => "index_repository_statuses_on_repository_id_and_platform_id", :unique => true
end
@ -533,12 +575,32 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.text "key", null: false
t.string "fingerprint", null: false
t.integer "user_id", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["fingerprint"], :name => "index_ssh_keys_on_fingerprint", :unique => true
t.index ["user_id"], :name => "index_ssh_keys_on_user_id"
end
create_table "statistics", force: true do |t|
t.integer "user_id", null: false
t.string "email", null: false
t.integer "project_id", null: false
t.string "project_name_with_owner", null: false
t.string "key", null: false
t.integer "counter", default: 0, null: false
t.datetime "activity_at", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.index ["activity_at"], :name => "index_statistics_on_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 ["user_id", "key", "activity_at"], :name => "index_statistics_on_user_id_and_key_and_activity_at"
t.index ["user_id", "project_id", "key", "activity_at"], :name => "index_statistics_on_all_keys", :unique => true
t.index ["user_id"], :name => "index_statistics_on_user_id"
end
create_table "subscribes", force: true do |t|
t.string "subscribeable_type"
t.integer "user_id"
@ -557,50 +619,10 @@ ActiveRecord::Schema.define(version: 20140924203530) do
t.string "status", default: "active"
t.text "description"
t.string "authentication_token", null: false
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["authentication_token"], :name => "index_tokens_on_authentication_token", :unique => true
t.index ["subject_id", "subject_type"], :name => "index_tokens_on_subject_id_and_subject_type"
end
create_table "users", force: true do |t|
t.string "name"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at"
t.datetime "updated_at"
t.text "ssh_key"
t.string "uname"
t.string "role"
t.string "language", default: "en"
t.integer "own_projects_count", default: 0, null: false
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.text "professional_experience"
t.string "site"
t.string "company"
t.string "location"
t.string "avatar_file_name"
t.string "avatar_content_type"
t.integer "avatar_file_size"
t.datetime "avatar_updated_at"
t.integer "failed_attempts", default: 0
t.string "unlock_token"
t.datetime "locked_at"
t.string "authentication_token"
t.integer "build_priority", default: 50
t.boolean "sound_notifications", default: true
t.boolean "hide_email", default: true, null: false
t.index ["authentication_token"], :name => "index_users_on_authentication_token"
t.index ["confirmation_token"], :name => "index_users_on_confirmation_token", :unique => true
t.index ["email"], :name => "index_users_on_email", :unique => true
t.index ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
t.index ["uname"], :name => "index_users_on_uname", :unique => true
t.index ["unlock_token"], :name => "index_users_on_unlock_token", :unique => true
end
end