daily 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.mdown +46 -0
- data/Rakefile +7 -0
- data/app/assets/images/rails.png +0 -0
- data/app/assets/javascripts/application.js +9 -0
- data/app/assets/stylesheets/application.css +16 -0
- data/app/assets/stylesheets/bootstrap.css +2467 -0
- data/app/controllers/application_controller.rb +14 -0
- data/app/controllers/files_controller.rb +5 -0
- data/app/controllers/main_controller.rb +5 -0
- data/app/controllers/reports_controller.rb +35 -0
- data/app/controllers/tables_controller.rb +20 -0
- data/app/controllers/users_controller.rb +28 -0
- data/app/formatters/html_formatter.rb +65 -0
- data/app/formatters/json_formatter.rb +81 -0
- data/app/helpers/application_helper.rb +85 -0
- data/app/jobs/generate_report_job.rb +13 -0
- data/app/models/report.rb +112 -0
- data/app/models/table.rb +65 -0
- data/app/models/user.rb +20 -0
- data/app/transforms/column_filter.rb +7 -0
- data/app/transforms/moving_average.rb +119 -0
- data/app/transforms/transform.rb +32 -0
- data/app/views/devise/sessions/new.erb +15 -0
- data/app/views/layouts/application.html.erb +40 -0
- data/app/views/main/home.erb +4 -0
- data/app/views/reports/_form.erb +14 -0
- data/app/views/reports/_list.erb +9 -0
- data/app/views/reports/edit.erb +2 -0
- data/app/views/reports/index.erb +3 -0
- data/app/views/reports/new.erb +2 -0
- data/app/views/reports/show.erb +23 -0
- data/app/views/tables/_form.erb +8 -0
- data/app/views/tables/_list.erb +9 -0
- data/app/views/tables/edit.erb +2 -0
- data/app/views/tables/index.erb +3 -0
- data/app/views/tables/new.erb +2 -0
- data/app/views/tables/show.erb +35 -0
- data/app/views/users/_form.erb +5 -0
- data/app/views/users/_items.erb +8 -0
- data/app/views/users/_list.erb +9 -0
- data/app/views/users/edit.erb +2 -0
- data/app/views/users/index.erb +3 -0
- data/app/views/users/new.erb +2 -0
- data/app/views/users/show.erb +4 -0
- data/config/application.rb +52 -0
- data/config/authorization_rules.rb +49 -0
- data/config/boot.rb +6 -0
- data/config/daily.example.yml +19 -0
- data/config/daily.yml +27 -0
- data/config/database.yml +25 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +32 -0
- data/config/environments/production.rb +63 -0
- data/config/environments/test.rb +39 -0
- data/config/initializers/backtrace_silencers.rb +7 -0
- data/config/initializers/devise.rb +212 -0
- data/config/initializers/inflections.rb +10 -0
- data/config/initializers/mime_types.rb +5 -0
- data/config/initializers/ruport.rb +5 -0
- data/config/initializers/secret_token.rb +7 -0
- data/config/initializers/session_store.rb +8 -0
- data/config/initializers/simple_form.rb +113 -0
- data/config/initializers/wrap_parameters.rb +14 -0
- data/config/locales/devise.en.yml +58 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/simple_form.en.yml +24 -0
- data/config/routes.rb +29 -0
- data/db/development.sqlite3 +0 -0
- data/db/migrate/20111109081414_devise_create_users.rb +28 -0
- data/db/migrate/20111111165640_create_tables.rb +14 -0
- data/db/migrate/20111112022333_add_name_to_tables.rb +9 -0
- data/db/migrate/20111112170802_add_reports.rb +15 -0
- data/db/migrate/20111113000026_add_guid_to_tables.rb +9 -0
- data/db/migrate/20111113073326_add_times_to_reports.rb +11 -0
- data/db/migrate/20111113075747_add_times_to_tables.rb +9 -0
- data/db/migrate/20111114041729_create_delayed_jobs.rb +21 -0
- data/db/migrate/20111114053016_add_report_to_delayed_jobs.rb +11 -0
- data/db/migrate/20111115014959_add_admin_to_users.rb +9 -0
- data/db/migrate/20111127065357_add_column_names_to_table.rb +9 -0
- data/db/migrate/20111203020425_add_transform_to_table.rb +16 -0
- data/db/migrate/20111214020029_add_formatter_data_to_reports.rb +8 -0
- data/db/schema.rb +80 -0
- data/db/seeds.rb +7 -0
- data/db/test.sqlite3 +0 -0
- data/lib/daily.rb +9 -0
- data/lib/daily/daily_config.rb +51 -0
- data/lib/daily/engine.rb +4 -0
- data/lib/daily/has_data.rb +52 -0
- data/lib/daily/shared_behaviors.rb +65 -0
- data/lib/daily/version.rb +3 -0
- data/lib/tasks/user.rake +24 -0
- metadata +454 -0
data/app/models/table.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
class Table < ActiveRecord::Base
|
2
|
+
include SharedBehaviors
|
3
|
+
|
4
|
+
belongs_to :user
|
5
|
+
has_many :reports
|
6
|
+
|
7
|
+
generate_guid :guid
|
8
|
+
|
9
|
+
validates_presence_of :user
|
10
|
+
validates_unique_presence_of :name
|
11
|
+
validates_stripped_presence_of :data
|
12
|
+
validates_stripped_presence_of :data_type
|
13
|
+
|
14
|
+
validate :data_type_known
|
15
|
+
|
16
|
+
serialize :column_names, Array
|
17
|
+
|
18
|
+
def sql?
|
19
|
+
data_type == "sql"
|
20
|
+
end
|
21
|
+
|
22
|
+
def result
|
23
|
+
fetch
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch
|
27
|
+
time = Time.now.to_i
|
28
|
+
|
29
|
+
out = fetch_data
|
30
|
+
out = apply_transform(out)
|
31
|
+
|
32
|
+
atts = {}
|
33
|
+
atts[:fetch_time_in_seconds] = Time.now.to_i - time
|
34
|
+
atts[:column_names] = out.column_names
|
35
|
+
self.attributes = atts
|
36
|
+
save unless new_record?
|
37
|
+
|
38
|
+
out
|
39
|
+
end
|
40
|
+
|
41
|
+
def test
|
42
|
+
# ouputs html of the table
|
43
|
+
begin
|
44
|
+
fetch.to_html.html_safe
|
45
|
+
rescue => e
|
46
|
+
out = "#{e.message}"
|
47
|
+
out += "\n\nTrace shown in development environment:\n#{e.backtrace.join("\n")}" if Rails.env.development?
|
48
|
+
out.gsub("\n", "<br/>").html_safe
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
def data_type_known
|
54
|
+
return if data_type.blank?
|
55
|
+
unless sql?
|
56
|
+
errors.add(:data_type, "is not known")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def fetch_data
|
61
|
+
return Ruport::Query.new(data).result if sql?
|
62
|
+
Ruport::Data::Table.new
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
# Include default devise modules. Others available are:
|
3
|
+
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
|
4
|
+
devise :database_authenticatable, :registerable,
|
5
|
+
:recoverable, :rememberable, :trackable, :validatable
|
6
|
+
|
7
|
+
# Setup accessible (or protected) attributes for your model
|
8
|
+
attr_accessible :email, :password, :password_confirmation, :remember_me
|
9
|
+
|
10
|
+
has_many :tables
|
11
|
+
has_many :reports
|
12
|
+
|
13
|
+
def role_symbols
|
14
|
+
return [] if new_record?
|
15
|
+
|
16
|
+
out = [:user]
|
17
|
+
out << :admin if admin?
|
18
|
+
out
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
class MovingAverage < Transform
|
2
|
+
def self.form_keys
|
3
|
+
[:columns, :days, :date]
|
4
|
+
end
|
5
|
+
|
6
|
+
def num_days
|
7
|
+
val = setting(:days).to_i
|
8
|
+
val <= 0 ? 7 : val
|
9
|
+
end
|
10
|
+
|
11
|
+
def date_column
|
12
|
+
setting(:date) || default_date_column || first_date_column
|
13
|
+
end
|
14
|
+
|
15
|
+
def result
|
16
|
+
cols = self.columns
|
17
|
+
datecol = self.date_column
|
18
|
+
daycount = self.num_days
|
19
|
+
|
20
|
+
avg_cols = cols.collect { |col| "#{col}_#{daycount}" }
|
21
|
+
|
22
|
+
out = Ruport::Data::Table.new( :column_names => [datecol] + cols + avg_cols)
|
23
|
+
|
24
|
+
data = day_data
|
25
|
+
days = data["days"]
|
26
|
+
first = data["earliest"]
|
27
|
+
latest = data["latest"]
|
28
|
+
|
29
|
+
current = first
|
30
|
+
while current <= latest do
|
31
|
+
row = {}
|
32
|
+
row[datecol] = current
|
33
|
+
|
34
|
+
cols.each do |col|
|
35
|
+
# this cols value for the day
|
36
|
+
value = 0
|
37
|
+
value = days[current][col].to_f if days[current]
|
38
|
+
|
39
|
+
# add them up
|
40
|
+
sum = 0
|
41
|
+
count = 0
|
42
|
+
check = current - daycount + 1
|
43
|
+
while check <= current
|
44
|
+
count += 1 unless check < first
|
45
|
+
sum += days[check][col].to_f if days[check]
|
46
|
+
check += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
row["#{col}_#{daycount}"] = sum / count
|
50
|
+
row["#{col}"] = value
|
51
|
+
end
|
52
|
+
|
53
|
+
out << row
|
54
|
+
current += 1
|
55
|
+
end
|
56
|
+
|
57
|
+
out
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def self.to_day(time_or_date)
|
63
|
+
time = Time.zone.parse(time_or_date.strftime("%Y-%m-%d %H:%M:%S %z"))
|
64
|
+
Date.new(time.year, time.month, time.day)
|
65
|
+
end
|
66
|
+
|
67
|
+
def day_data
|
68
|
+
earliest = Date.new(2032,1,1)
|
69
|
+
latest = Date.new(1492,1,1)
|
70
|
+
datenum = column_name_hash[date_column]
|
71
|
+
cols = self.columns
|
72
|
+
|
73
|
+
days = {}
|
74
|
+
|
75
|
+
table.each do |row|
|
76
|
+
time = row[datenum]
|
77
|
+
day = self.class.to_day(time)
|
78
|
+
latest = day if day > latest
|
79
|
+
earliest = day if day < earliest
|
80
|
+
|
81
|
+
days[day] ||= {}
|
82
|
+
cols.each do |col|
|
83
|
+
index = column_name_hash[col]
|
84
|
+
if index
|
85
|
+
days[day][col] ||= 0
|
86
|
+
days[day][col] += row[index].to_f
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
{"days" => days, "earliest" => earliest, "latest" => latest}
|
92
|
+
end
|
93
|
+
|
94
|
+
def column_name_hash
|
95
|
+
return @column_name_hash if @column_name_hash
|
96
|
+
@column_name_hash = {}
|
97
|
+
table.column_names.each_with_index do |name, i|
|
98
|
+
@column_name_hash[name.to_s] = i
|
99
|
+
end
|
100
|
+
@column_name_hash
|
101
|
+
end
|
102
|
+
|
103
|
+
def default_date_column
|
104
|
+
["created_at", "updated_at", "state_changed_at"].each do |col|
|
105
|
+
return col if column_name_hash[col]
|
106
|
+
end
|
107
|
+
return nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def first_date_column
|
111
|
+
return nil if table.size == 0
|
112
|
+
table[0].each_with_index do |val, i|
|
113
|
+
if val.is_a? Date or val.is_a? Time
|
114
|
+
return table.column_names[i]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Transform
|
2
|
+
def self.transforms
|
3
|
+
[ColumnFilter, MovingAverage]
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.display_name
|
7
|
+
name.demodulize.underscore.humanize.titleize
|
8
|
+
end
|
9
|
+
def self.form_keys
|
10
|
+
[:columns] # override to get more / different
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :table
|
14
|
+
attr_accessor :settings
|
15
|
+
def initialize(table, settings)
|
16
|
+
self.table = table
|
17
|
+
self.settings = (settings || {}).symbolize_keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def setting(key, default = nil)
|
21
|
+
val = settings[key.to_sym]
|
22
|
+
val.blank? ? default : val
|
23
|
+
end
|
24
|
+
|
25
|
+
def columns
|
26
|
+
setting(:columns, []).collect(&:to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
def result
|
30
|
+
raise("Transforms must override result")
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<h2>Sign in</h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
|
4
|
+
<div><%= f.label :email %><br />
|
5
|
+
<%= f.email_field :email %></div>
|
6
|
+
|
7
|
+
<div><%= f.label :password %><br />
|
8
|
+
<%= f.password_field :password %></div>
|
9
|
+
|
10
|
+
<% if devise_mapping.rememberable? -%>
|
11
|
+
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
|
12
|
+
<% end -%>
|
13
|
+
|
14
|
+
<div><%= f.submit "Sign in" %></div>
|
15
|
+
<% end %>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= page_title %></title>
|
5
|
+
<%= stylesheet_link_tag "application" %>
|
6
|
+
<%= javascript_include_tag "application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<div class="topbar">
|
11
|
+
<div class="fill">
|
12
|
+
<div class="container">
|
13
|
+
<a class="brand" href="<%= current_user ? user_root_path : root_path %>">Daily</a>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="container">
|
19
|
+
<% if header_title %>
|
20
|
+
<h1><%= header_title %></h1>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<% if notice %>
|
24
|
+
<div class="alert-message success">
|
25
|
+
<p><%= notice %></p>
|
26
|
+
</div>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<% if alert %>
|
30
|
+
<div class="alert-message error">
|
31
|
+
<p><%= alert %></p>
|
32
|
+
</div>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<%= yield %>
|
36
|
+
|
37
|
+
</div>
|
38
|
+
|
39
|
+
</body>
|
40
|
+
</html>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h3>Table: <%= link_to @report.table.name, table_path(@report.table) %></h3>
|
2
|
+
|
3
|
+
<%= simple_form_for [@report.table, @report] do |f| %>
|
4
|
+
<%= f.input :name %>
|
5
|
+
<%= f.input :filename unless @report.new_record? %>
|
6
|
+
|
7
|
+
<%= f.input :formatter, :collection => Report.formatters %>
|
8
|
+
<%= f.input :formatter_json, :as => :text %>
|
9
|
+
|
10
|
+
<%= f.input :transform, :collection => Transform.transforms, :label_method => :display_name, :value_method => :name %>
|
11
|
+
<%= f.input :transform_json, :as => :text %>
|
12
|
+
|
13
|
+
<%= f.button :submit %>
|
14
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<% title @report.name %>
|
2
|
+
<h3>Table: <%= link_to @report.table.name, table_path(@report.table) %></h3>
|
3
|
+
|
4
|
+
<% if @report.file_exists? %>
|
5
|
+
<h5>URL: <%= link_to @report.url(root_url), @report.url(root_url) %></h5>
|
6
|
+
<% else %>
|
7
|
+
<h5>URL: <%= @report.url(root_url) %></h5>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<h6>User: <%= "#{@report.user.email}" %></h6>
|
11
|
+
<h6>Running time: <%= report_time_run(@report) %></h6>
|
12
|
+
<h6>Last updated: <%= report_time_ago(@report) %></h6>
|
13
|
+
<h6>Next updated: <%= report_time_next(@report) %></h6>
|
14
|
+
<%= button_to "Queue Update Now", generate_table_report_path(@report.table, @report) if permitted_to? :generate, @report %>
|
15
|
+
|
16
|
+
<%= content_tag(:p, link_to("Edit", edit_table_report_path(@report.table, @report))) if permitted_to? :edit, @report %>
|
17
|
+
|
18
|
+
<%= formatter_display(@report) %>
|
19
|
+
|
20
|
+
<%= transform_display(@report) %>
|
21
|
+
|
22
|
+
<hr/>
|
23
|
+
<%= report_error_html(@report) %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= simple_form_for @table do |f| %>
|
2
|
+
<%= f.input :name %>
|
3
|
+
<%= f.input :data %>
|
4
|
+
|
5
|
+
<%= f.input :transform, :collection => Transform.transforms, :label_method => :display_name, :value_method => :name %>
|
6
|
+
<%= f.input :transform_json, :as => :text %>
|
7
|
+
<%= f.button :submit %>
|
8
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<% title @table.name %>
|
2
|
+
|
3
|
+
<h3>Reports</h3>
|
4
|
+
<p><%= link_to "New report from this table", new_table_report_path(@table) if permitted_to? :report, @table %></p>
|
5
|
+
<%= render "reports/list", :list => @table.reports %>
|
6
|
+
|
7
|
+
<hr/>
|
8
|
+
|
9
|
+
<h6>User: <%= "#{@table.user.email}" %></h6>
|
10
|
+
<h6>Type: <%= "#{@table.data_type}" %></h6>
|
11
|
+
<h6>Running time: <%= table_time_run(@table) %></h6>
|
12
|
+
<%= content_tag(:p, link_to("Edit", edit_table_path(@table))) if permitted_to? :edit, @table %>
|
13
|
+
|
14
|
+
<% if @test_html %>
|
15
|
+
<p><%= link_to "Hide Table Output", table_path(@table) %></p>
|
16
|
+
<%= @test_html %>
|
17
|
+
<% else %>
|
18
|
+
<p><%= link_to "See Table Output", table_path(@table, :test => true) %></p>
|
19
|
+
|
20
|
+
<% if @table.column_names and @table.column_names.size > 0 %>
|
21
|
+
<table>
|
22
|
+
<tr>
|
23
|
+
<% @table.column_names.each do |name| %>
|
24
|
+
<th><%= name %></th>
|
25
|
+
<% end %>
|
26
|
+
</tr>
|
27
|
+
</table>
|
28
|
+
<% end %>
|
29
|
+
<% end %>
|
30
|
+
|
31
|
+
<hr/>
|
32
|
+
|
33
|
+
<%= simple_format(@table.data) %>
|
34
|
+
|
35
|
+
<%= transform_display(@table) %>
|