daily 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.mdown +46 -0
  3. data/Rakefile +7 -0
  4. data/app/assets/images/rails.png +0 -0
  5. data/app/assets/javascripts/application.js +9 -0
  6. data/app/assets/stylesheets/application.css +16 -0
  7. data/app/assets/stylesheets/bootstrap.css +2467 -0
  8. data/app/controllers/application_controller.rb +14 -0
  9. data/app/controllers/files_controller.rb +5 -0
  10. data/app/controllers/main_controller.rb +5 -0
  11. data/app/controllers/reports_controller.rb +35 -0
  12. data/app/controllers/tables_controller.rb +20 -0
  13. data/app/controllers/users_controller.rb +28 -0
  14. data/app/formatters/html_formatter.rb +65 -0
  15. data/app/formatters/json_formatter.rb +81 -0
  16. data/app/helpers/application_helper.rb +85 -0
  17. data/app/jobs/generate_report_job.rb +13 -0
  18. data/app/models/report.rb +112 -0
  19. data/app/models/table.rb +65 -0
  20. data/app/models/user.rb +20 -0
  21. data/app/transforms/column_filter.rb +7 -0
  22. data/app/transforms/moving_average.rb +119 -0
  23. data/app/transforms/transform.rb +32 -0
  24. data/app/views/devise/sessions/new.erb +15 -0
  25. data/app/views/layouts/application.html.erb +40 -0
  26. data/app/views/main/home.erb +4 -0
  27. data/app/views/reports/_form.erb +14 -0
  28. data/app/views/reports/_list.erb +9 -0
  29. data/app/views/reports/edit.erb +2 -0
  30. data/app/views/reports/index.erb +3 -0
  31. data/app/views/reports/new.erb +2 -0
  32. data/app/views/reports/show.erb +23 -0
  33. data/app/views/tables/_form.erb +8 -0
  34. data/app/views/tables/_list.erb +9 -0
  35. data/app/views/tables/edit.erb +2 -0
  36. data/app/views/tables/index.erb +3 -0
  37. data/app/views/tables/new.erb +2 -0
  38. data/app/views/tables/show.erb +35 -0
  39. data/app/views/users/_form.erb +5 -0
  40. data/app/views/users/_items.erb +8 -0
  41. data/app/views/users/_list.erb +9 -0
  42. data/app/views/users/edit.erb +2 -0
  43. data/app/views/users/index.erb +3 -0
  44. data/app/views/users/new.erb +2 -0
  45. data/app/views/users/show.erb +4 -0
  46. data/config/application.rb +52 -0
  47. data/config/authorization_rules.rb +49 -0
  48. data/config/boot.rb +6 -0
  49. data/config/daily.example.yml +19 -0
  50. data/config/daily.yml +27 -0
  51. data/config/database.yml +25 -0
  52. data/config/environment.rb +5 -0
  53. data/config/environments/development.rb +32 -0
  54. data/config/environments/production.rb +63 -0
  55. data/config/environments/test.rb +39 -0
  56. data/config/initializers/backtrace_silencers.rb +7 -0
  57. data/config/initializers/devise.rb +212 -0
  58. data/config/initializers/inflections.rb +10 -0
  59. data/config/initializers/mime_types.rb +5 -0
  60. data/config/initializers/ruport.rb +5 -0
  61. data/config/initializers/secret_token.rb +7 -0
  62. data/config/initializers/session_store.rb +8 -0
  63. data/config/initializers/simple_form.rb +113 -0
  64. data/config/initializers/wrap_parameters.rb +14 -0
  65. data/config/locales/devise.en.yml +58 -0
  66. data/config/locales/en.yml +5 -0
  67. data/config/locales/simple_form.en.yml +24 -0
  68. data/config/routes.rb +29 -0
  69. data/db/development.sqlite3 +0 -0
  70. data/db/migrate/20111109081414_devise_create_users.rb +28 -0
  71. data/db/migrate/20111111165640_create_tables.rb +14 -0
  72. data/db/migrate/20111112022333_add_name_to_tables.rb +9 -0
  73. data/db/migrate/20111112170802_add_reports.rb +15 -0
  74. data/db/migrate/20111113000026_add_guid_to_tables.rb +9 -0
  75. data/db/migrate/20111113073326_add_times_to_reports.rb +11 -0
  76. data/db/migrate/20111113075747_add_times_to_tables.rb +9 -0
  77. data/db/migrate/20111114041729_create_delayed_jobs.rb +21 -0
  78. data/db/migrate/20111114053016_add_report_to_delayed_jobs.rb +11 -0
  79. data/db/migrate/20111115014959_add_admin_to_users.rb +9 -0
  80. data/db/migrate/20111127065357_add_column_names_to_table.rb +9 -0
  81. data/db/migrate/20111203020425_add_transform_to_table.rb +16 -0
  82. data/db/migrate/20111214020029_add_formatter_data_to_reports.rb +8 -0
  83. data/db/schema.rb +80 -0
  84. data/db/seeds.rb +7 -0
  85. data/db/test.sqlite3 +0 -0
  86. data/lib/daily.rb +9 -0
  87. data/lib/daily/daily_config.rb +51 -0
  88. data/lib/daily/engine.rb +4 -0
  89. data/lib/daily/has_data.rb +52 -0
  90. data/lib/daily/shared_behaviors.rb +65 -0
  91. data/lib/daily/version.rb +3 -0
  92. data/lib/tasks/user.rake +24 -0
  93. metadata +454 -0
@@ -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
@@ -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,7 @@
1
+ class ColumnFilter < Transform
2
+ def result
3
+ to_remove = table.column_names - columns
4
+ table.remove_columns(to_remove)
5
+ table
6
+ end
7
+ 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,4 @@
1
+ <% title "Welcome #{current_user.email}" %>
2
+ <%= content_tag(:p, link_to("Update Account", account_path)) if permitted_to? :account, current_user %>
3
+
4
+ <%= render 'users/items', :user => current_user %>
@@ -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,9 @@
1
+ <% if list.size > 0 %>
2
+ <ul>
3
+ <% list.each do |report| %>
4
+ <% if permitted_to? :show, report %>
5
+ <li><%= link_to report.name, table_report_path(report.table, report) %></li>
6
+ <% end %>
7
+ <% end %>
8
+ </ul>
9
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <% title "Edit Report: #{@report.name}" %>
2
+ <%= render 'form' %>
@@ -0,0 +1,3 @@
1
+ <% title "Reports" %>
2
+
3
+ <%= render "reports/list", :list => @reports %>
@@ -0,0 +1,2 @@
1
+ <% title "New Report" %>
2
+ <%= render 'form' %>
@@ -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,9 @@
1
+ <% if list.size > 0 %>
2
+ <ul>
3
+ <% list.each do |table| %>
4
+ <% if permitted_to? :show, table %>
5
+ <li><%= link_to table.name, table %></li>
6
+ <% end %>
7
+ <% end %>
8
+ </ul>
9
+ <% end %>
@@ -0,0 +1,2 @@
1
+ <% title "Edit Table: #{@table.name}" %>
2
+ <%= render 'form' %>
@@ -0,0 +1,3 @@
1
+ <% title "Tables" %>
2
+
3
+ <%= render "tables/list", :list => @tables %>
@@ -0,0 +1,2 @@
1
+ <% title "New Table" %>
2
+ <%= render 'form' %>
@@ -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) %>