watch_tower 0.0.0.1
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.
- data/.gitignore +10 -0
- data/.todo +33 -0
- data/.travis.yml +14 -0
- data/Gemfile +43 -0
- data/Guardfile +25 -0
- data/MIT-LICENSE +20 -0
- data/README.md +38 -0
- data/Rakefile +8 -0
- data/TODO +17 -0
- data/bin/watchtower +10 -0
- data/ci/adapters/jruby-mysql.yml +8 -0
- data/ci/adapters/jruby-postgresql.yml +6 -0
- data/ci/adapters/jruby-sqlite.yml +6 -0
- data/ci/adapters/ruby-mysql.yml +8 -0
- data/ci/adapters/ruby-postgresql.yml +6 -0
- data/ci/adapters/ruby-sqlite.yml +6 -0
- data/ci/travis.rb +102 -0
- data/lib/watch_tower.rb +60 -0
- data/lib/watch_tower/appscript.rb +22 -0
- data/lib/watch_tower/cli.rb +15 -0
- data/lib/watch_tower/cli/.gitkeep +0 -0
- data/lib/watch_tower/cli/install.rb +63 -0
- data/lib/watch_tower/cli/open.rb +24 -0
- data/lib/watch_tower/cli/start.rb +140 -0
- data/lib/watch_tower/config.rb +38 -0
- data/lib/watch_tower/core_ext.rb +4 -0
- data/lib/watch_tower/core_ext/.gitkeep +0 -0
- data/lib/watch_tower/editor.rb +17 -0
- data/lib/watch_tower/editor/.gitkeep +0 -0
- data/lib/watch_tower/editor/base_appscript.rb +34 -0
- data/lib/watch_tower/editor/base_ps.rb +6 -0
- data/lib/watch_tower/editor/textmate.rb +17 -0
- data/lib/watch_tower/editor/xcode.rb +22 -0
- data/lib/watch_tower/errors.rb +25 -0
- data/lib/watch_tower/eye.rb +79 -0
- data/lib/watch_tower/project.rb +14 -0
- data/lib/watch_tower/project/.gitkeep +0 -0
- data/lib/watch_tower/project/any_based.rb +22 -0
- data/lib/watch_tower/project/git_based.rb +86 -0
- data/lib/watch_tower/project/init.rb +38 -0
- data/lib/watch_tower/project/path_based.rb +144 -0
- data/lib/watch_tower/server.rb +62 -0
- data/lib/watch_tower/server/.gitkeep +0 -0
- data/lib/watch_tower/server/app.rb +37 -0
- data/lib/watch_tower/server/assets/images/WatchTower.jpg +0 -0
- data/lib/watch_tower/server/assets/images/percentage.png +0 -0
- data/lib/watch_tower/server/assets/javascripts/application.js +3 -0
- data/lib/watch_tower/server/assets/javascripts/percentage.coffee +8 -0
- data/lib/watch_tower/server/assets/stylesheets/application.css +7 -0
- data/lib/watch_tower/server/assets/stylesheets/global.sass +71 -0
- data/lib/watch_tower/server/assets/stylesheets/project.sass +59 -0
- data/lib/watch_tower/server/configurations.rb +10 -0
- data/lib/watch_tower/server/configurations/asset.rb +43 -0
- data/lib/watch_tower/server/database.rb +105 -0
- data/lib/watch_tower/server/db/migrate/001_create_projects.rb +15 -0
- data/lib/watch_tower/server/db/migrate/002_create_files.rb +16 -0
- data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +12 -0
- data/lib/watch_tower/server/db/migrate/004_create_durations.rb +14 -0
- data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +6 -0
- data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +6 -0
- data/lib/watch_tower/server/decorator.rb +21 -0
- data/lib/watch_tower/server/decorator/application_decorator.rb +91 -0
- data/lib/watch_tower/server/decorator/file_decorator.rb +38 -0
- data/lib/watch_tower/server/decorator/project_decorator.rb +51 -0
- data/lib/watch_tower/server/helpers.rb +13 -0
- data/lib/watch_tower/server/helpers/asset.rb +29 -0
- data/lib/watch_tower/server/helpers/improved_partials.rb +41 -0
- data/lib/watch_tower/server/models/duration.rb +11 -0
- data/lib/watch_tower/server/models/file.rb +31 -0
- data/lib/watch_tower/server/models/project.rb +17 -0
- data/lib/watch_tower/server/models/time_entry.rb +64 -0
- data/lib/watch_tower/server/public/assets/WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg +0 -0
- data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +107 -0
- data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +9359 -0
- data/lib/watch_tower/server/public/assets/percentage-d8589e21a5fc85d32a445f531ff8ab95.png +0 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-ui.js +11729 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery.js +8981 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery_ujs.js +363 -0
- data/lib/watch_tower/server/views/.gitkeep +0 -0
- data/lib/watch_tower/server/views/_file.haml +9 -0
- data/lib/watch_tower/server/views/_project.haml +13 -0
- data/lib/watch_tower/server/views/index.haml +7 -0
- data/lib/watch_tower/server/views/layout.haml +32 -0
- data/lib/watch_tower/server/views/project.haml +12 -0
- data/lib/watch_tower/templates/config.yml +146 -0
- data/lib/watch_tower/templates/watchtower.plist +23 -0
- data/lib/watch_tower/version.rb +8 -0
- data/spec/factories.rb +45 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/active_record.rb +44 -0
- data/spec/support/factory_girl.rb +6 -0
- data/spec/support/launchy.rb +3 -0
- data/spec/support/sinatra.rb +10 -0
- data/spec/support/timecop.rb +7 -0
- data/spec/watch_tower/appscript_spec.rb +6 -0
- data/spec/watch_tower/cli/install_spec.rb +16 -0
- data/spec/watch_tower/cli/open_spec.rb +14 -0
- data/spec/watch_tower/cli/start_spec.rb +17 -0
- data/spec/watch_tower/cli_spec.rb +15 -0
- data/spec/watch_tower/config_spec.rb +25 -0
- data/spec/watch_tower/editor/textmate_spec.rb +43 -0
- data/spec/watch_tower/editor/xcode_spec.rb +43 -0
- data/spec/watch_tower/editor_spec.rb +19 -0
- data/spec/watch_tower/eye_spec.rb +130 -0
- data/spec/watch_tower/project/git_based_spec.rb +131 -0
- data/spec/watch_tower/project/path_based_spec.rb +111 -0
- data/spec/watch_tower/project_spec.rb +82 -0
- data/spec/watch_tower/server/app_spec.rb +186 -0
- data/spec/watch_tower/server/decorator/project_decorator_spec.rb +60 -0
- data/spec/watch_tower/server/models/file_spec.rb +284 -0
- data/spec/watch_tower/server/models/project_spec.rb +165 -0
- data/spec/watch_tower/server/models/time_entry_spec.rb +37 -0
- data/spec/watch_tower/server_spec.rb +4 -0
- data/watch_tower.gemspec +80 -0
- metadata +450 -0
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Sinatra
|
|
2
|
+
require 'sinatra'
|
|
3
|
+
|
|
4
|
+
module WatchTower
|
|
5
|
+
module Server
|
|
6
|
+
class App < ::Sinatra::Application
|
|
7
|
+
# Helper
|
|
8
|
+
include Helpers::ImprovedPartials
|
|
9
|
+
include Helpers::Asset
|
|
10
|
+
|
|
11
|
+
# Include Decorator
|
|
12
|
+
include Decorator
|
|
13
|
+
|
|
14
|
+
# Configurations
|
|
15
|
+
include Configurations::Asset
|
|
16
|
+
|
|
17
|
+
# Routes
|
|
18
|
+
paths :root => '/'
|
|
19
|
+
paths :project => '/project/:id'
|
|
20
|
+
|
|
21
|
+
# The index action
|
|
22
|
+
get :root do
|
|
23
|
+
@title = "Projects"
|
|
24
|
+
@projects = ProjectDecorator.decorate(Project.worked_on)
|
|
25
|
+
|
|
26
|
+
haml :index
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
get :project do
|
|
30
|
+
@project = ProjectDecorator.find(params[:id])
|
|
31
|
+
@title = "Project - #{@project.name.camelcase}"
|
|
32
|
+
|
|
33
|
+
haml :project
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
|
5
|
+
*= require_self
|
|
6
|
+
*= require_tree .
|
|
7
|
+
*/
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
$footer_text_color: #000
|
|
2
|
+
$footer_bg: #D6AFAF
|
|
3
|
+
$link_color: +darken($footer_bg, 20%)
|
|
4
|
+
|
|
5
|
+
h1
|
|
6
|
+
font-size: 2em
|
|
7
|
+
h2
|
|
8
|
+
font-size: 1em
|
|
9
|
+
|
|
10
|
+
#logo
|
|
11
|
+
a
|
|
12
|
+
color: #000
|
|
13
|
+
text-decoration: none
|
|
14
|
+
|
|
15
|
+
// Background stylesheet
|
|
16
|
+
display: block
|
|
17
|
+
// TODO: Very bad bad bad idea to hardcode assets, how can we reference an asset from sass ?
|
|
18
|
+
background: url('WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg') no-repeat
|
|
19
|
+
width: 390px
|
|
20
|
+
height: 94px
|
|
21
|
+
|
|
22
|
+
&:visited, &:hover
|
|
23
|
+
text-decoration: none
|
|
24
|
+
|
|
25
|
+
h1
|
|
26
|
+
float: left
|
|
27
|
+
margin-top: 30px
|
|
28
|
+
margin-left: 180px
|
|
29
|
+
|
|
30
|
+
.clearfix
|
|
31
|
+
clear: both
|
|
32
|
+
|
|
33
|
+
a
|
|
34
|
+
color: $link_color
|
|
35
|
+
text-decoration: none
|
|
36
|
+
|
|
37
|
+
&:hover, &:visited
|
|
38
|
+
text-decoration: none
|
|
39
|
+
|
|
40
|
+
body
|
|
41
|
+
background: #f7f7f7
|
|
42
|
+
color: #000
|
|
43
|
+
font-family: Arial, Helvetica, sans-serif
|
|
44
|
+
|
|
45
|
+
#wrapper
|
|
46
|
+
width: 960px
|
|
47
|
+
margin: 0 auto
|
|
48
|
+
|
|
49
|
+
#main
|
|
50
|
+
border: 1px solid #cdcdcd
|
|
51
|
+
-webkit-border-radius: 5px
|
|
52
|
+
-moz-border-radius: 5px
|
|
53
|
+
border-radius: 5px
|
|
54
|
+
padding: 10px
|
|
55
|
+
min-height: 200px
|
|
56
|
+
background: #fff
|
|
57
|
+
|
|
58
|
+
#footer
|
|
59
|
+
width: 960px
|
|
60
|
+
text-align: center
|
|
61
|
+
background: $footer_bg
|
|
62
|
+
color: $footer_text_color
|
|
63
|
+
padding: 5px 0
|
|
64
|
+
font-size: 12px
|
|
65
|
+
|
|
66
|
+
a
|
|
67
|
+
color: $footer_text_color
|
|
68
|
+
text-decoration: none
|
|
69
|
+
|
|
70
|
+
&:visited, &:hover
|
|
71
|
+
text-decoration: none
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
=project_name
|
|
2
|
+
float: left
|
|
3
|
+
width: 200px
|
|
4
|
+
|
|
5
|
+
=percentage
|
|
6
|
+
width: 310px
|
|
7
|
+
float: left
|
|
8
|
+
.percentage_img
|
|
9
|
+
height: 20px
|
|
10
|
+
|
|
11
|
+
=elapsed
|
|
12
|
+
float: left
|
|
13
|
+
|
|
14
|
+
=header_text
|
|
15
|
+
font-size: 20px
|
|
16
|
+
text-decoration: underline
|
|
17
|
+
|
|
18
|
+
#projects
|
|
19
|
+
header
|
|
20
|
+
.name
|
|
21
|
+
+project_name
|
|
22
|
+
+header_text
|
|
23
|
+
|
|
24
|
+
.percentage
|
|
25
|
+
+percentage
|
|
26
|
+
+header_text
|
|
27
|
+
.elapsed
|
|
28
|
+
+elapsed
|
|
29
|
+
+header_text
|
|
30
|
+
|
|
31
|
+
.project
|
|
32
|
+
.name
|
|
33
|
+
+project_name
|
|
34
|
+
.percentage_img_container
|
|
35
|
+
+percentage
|
|
36
|
+
.elapsed
|
|
37
|
+
+elapsed
|
|
38
|
+
|
|
39
|
+
#project
|
|
40
|
+
#files
|
|
41
|
+
header
|
|
42
|
+
.path
|
|
43
|
+
+header_text
|
|
44
|
+
float: left
|
|
45
|
+
width: 600px
|
|
46
|
+
.elapsed
|
|
47
|
+
+header_text
|
|
48
|
+
float: left
|
|
49
|
+
|
|
50
|
+
.path
|
|
51
|
+
float: left
|
|
52
|
+
width: 600px
|
|
53
|
+
.elapsed
|
|
54
|
+
float: left
|
|
55
|
+
.percentage_img_container
|
|
56
|
+
width: 310px
|
|
57
|
+
float: left
|
|
58
|
+
.percentage_img
|
|
59
|
+
height: 20px
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Asset Pipeline
|
|
2
|
+
require 'coffee-script'
|
|
3
|
+
require 'uglifier'
|
|
4
|
+
require 'sass'
|
|
5
|
+
require 'sprockets'
|
|
6
|
+
|
|
7
|
+
module WatchTower
|
|
8
|
+
module Server
|
|
9
|
+
module Configurations
|
|
10
|
+
module Asset
|
|
11
|
+
def self.included(base)
|
|
12
|
+
base.class_eval <<-END, __FILE__, __LINE__ + 1
|
|
13
|
+
# Code taken from
|
|
14
|
+
# https://github.com/stevehodgkiss/sinatra-asset-pipeline/blob/master/app.rb#L11
|
|
15
|
+
set :sprockets, Sprockets::Environment.new(SERVER_PATH)
|
|
16
|
+
set :precompile, [ /\w+\.(?!js|css).+/, /application.(css|js)$/ ]
|
|
17
|
+
set :assets_prefix, 'assets'
|
|
18
|
+
set :assets_path, ::File.join(SERVER_PATH, 'public', assets_prefix)
|
|
19
|
+
|
|
20
|
+
configure do
|
|
21
|
+
# Lib
|
|
22
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'lib', 'assets', 'stylesheets'))
|
|
23
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'lib', 'assets', 'javascripts'))
|
|
24
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'lib', 'assets', 'images'))
|
|
25
|
+
|
|
26
|
+
# Vendor
|
|
27
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'vendor', 'assets', 'stylesheets'))
|
|
28
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'vendor', 'assets', 'javascripts'))
|
|
29
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'vendor', 'assets', 'images'))
|
|
30
|
+
|
|
31
|
+
# Assets
|
|
32
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'assets', 'stylesheets'))
|
|
33
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'assets', 'javascripts'))
|
|
34
|
+
sprockets.append_path(::File.join(SERVER_PATH, 'assets', 'images'))
|
|
35
|
+
|
|
36
|
+
sprockets.context_class.send :extend, Helpers::Asset
|
|
37
|
+
end
|
|
38
|
+
END
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'active_record'
|
|
2
|
+
|
|
3
|
+
module WatchTower
|
|
4
|
+
module Server
|
|
5
|
+
module Database
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
# Start the database server
|
|
9
|
+
#
|
|
10
|
+
# see #connect!
|
|
11
|
+
# see #migrate!
|
|
12
|
+
# @param [Hash] options
|
|
13
|
+
def start!(options = {})
|
|
14
|
+
LOG.debug("#{__FILE__}:#{__LINE__}: Starting the database server.")
|
|
15
|
+
|
|
16
|
+
# Connect to the Database
|
|
17
|
+
connect!
|
|
18
|
+
|
|
19
|
+
# Migrate the database
|
|
20
|
+
migrate!
|
|
21
|
+
rescue DatabaseConfigNotFoundError
|
|
22
|
+
STDERR.puts "Database configurations are missing, please edit #{Config::CONFIG_FILE} and try again."
|
|
23
|
+
exit(1)
|
|
24
|
+
rescue ::ActiveRecord::ConnectionNotEstablished => e
|
|
25
|
+
STDERR.puts "There was an error connecting to the database: #{e}"
|
|
26
|
+
exit(1)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Stop the database server
|
|
30
|
+
#
|
|
31
|
+
# see #disconnect!
|
|
32
|
+
# @param [Hash] options
|
|
33
|
+
def stop!(options = {})
|
|
34
|
+
# Disconnect from the database
|
|
35
|
+
disconnect!
|
|
36
|
+
rescue DatabaseConfigNotFoundError
|
|
37
|
+
STDERR.puts "Database configurations are missing, please edit #{Config::CONFIG_FILE} and try again."
|
|
38
|
+
exit(1)
|
|
39
|
+
rescue ::ActiveRecord::ConnectionNotEstablished => e
|
|
40
|
+
STDERR.puts "There was an error connecting to the database: #{e}"
|
|
41
|
+
exit(1)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def is_connected?
|
|
45
|
+
ActiveRecord::Base.connected?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def is_migrated?
|
|
49
|
+
ActiveRecord::Migrator.current_version ==
|
|
50
|
+
ActiveRecord::Migrator.migrations(MIGRATIONS_PATH).last.version
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
protected
|
|
54
|
+
# Connect to the database
|
|
55
|
+
def connect!
|
|
56
|
+
return if is_connected?
|
|
57
|
+
LOG.debug("#{__FILE__}:#{__LINE__}: Connecting to the database.")
|
|
58
|
+
# Create a connection
|
|
59
|
+
ActiveRecord::Base.establish_connection(db_config)
|
|
60
|
+
|
|
61
|
+
# Create a looger
|
|
62
|
+
logger unless ENV['WATCH_TOWER_ENV'] == 'production'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Disconnect from the database
|
|
66
|
+
# TODO: Implement this function
|
|
67
|
+
def disconnect!
|
|
68
|
+
raise NotImplementedError
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Migrate the database
|
|
72
|
+
def migrate!
|
|
73
|
+
return if is_migrated?
|
|
74
|
+
LOG.debug("#{__FILE__}:#{__LINE__}: Migrating the database.")
|
|
75
|
+
# Connect to the database
|
|
76
|
+
connect!
|
|
77
|
+
|
|
78
|
+
# Migrate the database
|
|
79
|
+
ActiveRecord::Migrator.migrate(MIGRATIONS_PATH)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Get the database configuration
|
|
83
|
+
def db_config
|
|
84
|
+
db_config = Config.try(:[], :database).try(:[], ENV['WATCH_TOWER_ENV'])
|
|
85
|
+
raise DatabaseConfigNotFoundError unless db_config
|
|
86
|
+
if db_config[:adapter] =~ /sqlite/ && db_config[:database] != ":memory:"
|
|
87
|
+
db_config[:database] = ::File.expand_path(db_config[:database])
|
|
88
|
+
end
|
|
89
|
+
db_config
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Set the logger
|
|
93
|
+
def logger
|
|
94
|
+
ActiveRecord::Base.logger ||= Logger.new ::File.open(log_path, 'a')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Get the log file's absolute path
|
|
98
|
+
#
|
|
99
|
+
# @return [String] The database log file depending on the environment
|
|
100
|
+
def log_path
|
|
101
|
+
::File.join(LOG_PATH, "#{ENV['WATCH_TOWER_ENV']}_database.log")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class CreateProjects < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :projects do |t|
|
|
4
|
+
t.string :name, null: false
|
|
5
|
+
t.string :path, null: false
|
|
6
|
+
t.integer :elapsed_time, default: 0
|
|
7
|
+
t.integer :files_count
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :projects, :name
|
|
13
|
+
add_index :projects, :path
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateFiles < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :files do |t|
|
|
4
|
+
t.references :project, null: false
|
|
5
|
+
t.string :path, null: false
|
|
6
|
+
t.integer :elapsed_time, default: 0
|
|
7
|
+
t.integer :time_entries_count
|
|
8
|
+
t.integer :durations_count
|
|
9
|
+
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :files, :project_id
|
|
14
|
+
add_index :files, :path, unique: true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateDurations < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :durations do |t|
|
|
4
|
+
t.references :file, null: false
|
|
5
|
+
t.date :date, null: false
|
|
6
|
+
t.integer :duration, default: 0
|
|
7
|
+
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :durations, :file_id
|
|
12
|
+
add_index :durations, :date
|
|
13
|
+
end
|
|
14
|
+
end
|