├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Guardfile.example ├── README.md ├── Rakefile ├── app.json ├── app ├── assets │ ├── images │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ ├── fonts │ │ │ └── DIN_Medium.ttf │ │ ├── ktra-header-logo@2x.png │ │ ├── ktra.svg │ │ └── rails.png │ ├── javascripts │ │ ├── application.js │ │ ├── ktra.js.coffee │ │ ├── tasks.js.coffee │ │ └── welcome.js.coffee │ └── stylesheets │ │ ├── application.css.sass │ │ ├── mixin.css.sass │ │ ├── style.css.sass │ │ └── variables.css.sass ├── controllers │ ├── accounts_controller.rb │ ├── application_controller.rb │ ├── sessions_controller.rb │ ├── statuses_controller.rb │ ├── tasks_controller.rb │ ├── weeks_controller.rb │ └── welcome_controller.rb ├── helpers │ ├── application_helper.rb │ └── tasks_helper.rb ├── mailers │ └── .gitkeep ├── models │ ├── .gitkeep │ ├── task.rb │ ├── user.rb │ └── week.rb └── views │ ├── accounts │ └── show.json.jbuilder │ ├── application │ ├── _footer.html.haml │ ├── _ga.html.haml │ ├── _head.html.haml │ └── _header.html.haml │ ├── layouts │ ├── application.html.haml │ └── welcome.html.haml │ ├── statuses │ └── update.js.erb │ ├── tasks │ ├── _edit.html.haml │ ├── _form.html.haml │ ├── _task.html.haml │ ├── _tasks.html.haml │ ├── create.js.erb │ ├── destroy.js.erb │ ├── edit.js.erb │ ├── form │ │ ├── _done.html.haml │ │ ├── _points.html.haml │ │ ├── _restart.html.haml │ │ ├── _start.html.haml │ │ ├── _stop.html.haml │ │ └── _title.html.haml │ ├── index.html.haml │ ├── statuses │ │ ├── _doing.html.haml │ │ ├── _done.html.haml │ │ └── _unstarted.html.haml │ ├── task │ │ ├── _doing.html.haml │ │ ├── _done.html.haml │ │ └── _unstarted.html.haml │ └── update.js.erb │ ├── weeks │ ├── _summary.html.haml │ ├── index.html.haml │ └── show.html.haml │ └── welcome │ └── index.html.haml ├── bin ├── rails ├── rake ├── rspec └── spring ├── circle.yml ├── config.ru ├── config ├── application.example.yml ├── application.rb ├── boot.rb ├── compass.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ ├── staging.rb │ └── test.rb ├── initializers │ ├── backtrace_silencers.rb │ ├── bugsnag.rb │ ├── devise.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ ├── devise │ │ ├── en.yml │ │ └── ja.yml │ ├── en.yml │ └── ja.yml ├── routes.rb └── secrets.yml ├── db ├── migrate │ ├── 20130425112957_create_tasks.rb │ ├── 20130619112425_create_iterations.rb │ ├── 20130619113001_add_iteration_id_to_tasks.rb │ ├── 20130815115856_create_users.rb │ ├── 20140306103013_add_user_id_to_tasks.rb │ └── 20140401074621_change_iterations_to_weeks.rb ├── schema.rb └── seeds.rb ├── doc ├── README_FOR_APP ├── apple-touch-icon.psd ├── favicon │ ├── favicon-128.png │ ├── favicon-128.psd │ ├── favicon-16.png │ ├── favicon-32.png │ ├── favicon-48.png │ ├── favicon-96.png │ └── favicon.psd ├── ktra-design.ai ├── ktra-goods-base.ai └── ktra-tshirt.png ├── lib ├── assets │ └── .gitkeep └── tasks │ └── .gitkeep ├── log └── .gitkeep ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── spec ├── controllers │ ├── accounts_controller_spec.rb │ ├── statuses_controller_spec.rb │ ├── tasks_controller_spec.rb │ └── weeks_controller_spec.rb ├── factories │ ├── .gitkeep │ ├── tasks.rb │ ├── users.rb │ └── weeks.rb ├── features │ ├── .gitkeep │ ├── sign_in_spec.rb │ └── tasks_spec.rb ├── models │ ├── .gitkeep │ ├── task_spec.rb │ ├── user_spec.rb │ └── week_spec.rb ├── rails_helper.rb ├── routing │ └── .gitkeep ├── spec_helper.rb └── support │ ├── controller.rb │ └── feature_macros.rb ├── vendor ├── assets │ ├── javascripts │ │ └── .gitkeep │ └── stylesheets │ │ └── .gitkeep └── plugins │ └── .gitkeep └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | **.swp 2 | **.orig 3 | *.rbc 4 | *.sassc 5 | .DS_Store 6 | .env 7 | .jhw-cache 8 | .pow* 9 | .pryrc 10 | .rspec 11 | .rvmrc 12 | .sass-cache 13 | .ruby-version 14 | /.bundle 15 | /coverage/ 16 | /db/*.sqlite3 17 | /db/import/* 18 | /log/* 19 | /public/system/* 20 | /spec/tmp/* 21 | /tmp/* 22 | /vendor/bin 23 | /vendor/bundle 24 | Guardfile 25 | capybara-*.html 26 | config/application.yml 27 | config/environments/*.local.yml 28 | config/settings.local.yml 29 | config/settings/*.local.yml 30 | erd.pdf 31 | pickle-email-*.html 32 | public/assets 33 | public/assets-test 34 | rerun.txt 35 | spec/tmp 36 | 37 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby '2.3.4' 3 | 4 | gem 'rails', '4.1.10' 5 | 6 | # APIs 7 | gem 'bugsnag' 8 | 9 | # Auth 10 | gem 'devise' 11 | gem 'omniauth' 12 | gem 'omniauth-twitter' 13 | 14 | gem 'pg' 15 | 16 | group :development do 17 | # Debugs 18 | gem 'awesome_print' 19 | gem 'better_errors' 20 | gem 'binding_of_caller' 21 | gem 'bullet' 22 | gem 'hirb' 23 | gem 'hirb-unicode' 24 | gem 'letter_opener' 25 | gem 'pry-byebug' 26 | gem 'pry-doc' 27 | gem 'pry-rails' 28 | gem 'pry-stack_explorer' 29 | gem 'pry-byebug' 30 | gem 'quiet_assets' 31 | gem 'tapp' 32 | gem 'view_source_map' 33 | gem 'i18n-tasks' 34 | gem 'thin' 35 | gem 'spring' 36 | gem 'spring-commands-rspec' 37 | end 38 | 39 | group :test, :development do 40 | # TDD 41 | gem 'brakeman' 42 | gem 'capybara' 43 | gem 'database_cleaner' 44 | gem 'delorean' 45 | gem 'factory_girl' 46 | gem 'factory_girl_rails' 47 | gem 'faker' 48 | #gem 'guard' 49 | #gem 'guard-rspec', require: false 50 | #gem 'guard-sprockets2' 51 | gem 'json_expressions' 52 | gem 'launchy' 53 | gem 'nokogiri' 54 | gem 'poltergeist' 55 | gem 'rails-db-resetup' 56 | gem 'rb-fsevent', require: RUBY_PLATFORM.downcase =~ /darwin/ ? 'rb-fsevent' : false 57 | gem 'rspec-rails' 58 | gem 'shoulda-matchers' 59 | gem 'spring' 60 | gem 'spring-commands-rspec' 61 | gem 'sqlite3' 62 | end 63 | 64 | gem 'coffee-rails', '~> 4.0.0' 65 | gem 'compass-rails' 66 | gem 'uglifier', '>= 1.3.0' 67 | gem 'sass-rails', '~> 4.0.0' 68 | gem 'jquery-rails' 69 | gem 'jquery-ui-rails' 70 | gem 'haml-rails' 71 | gem 'erb2haml' 72 | gem 'font-awesome-rails' 73 | gem 'figaro' 74 | gem 'unicorn' 75 | gem 'jbuilder', '~> 1.2' 76 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.1.10) 5 | actionpack (= 4.1.10) 6 | actionview (= 4.1.10) 7 | mail (~> 2.5, >= 2.5.4) 8 | actionpack (4.1.10) 9 | actionview (= 4.1.10) 10 | activesupport (= 4.1.10) 11 | rack (~> 1.5.2) 12 | rack-test (~> 0.6.2) 13 | actionview (4.1.10) 14 | activesupport (= 4.1.10) 15 | builder (~> 3.1) 16 | erubis (~> 2.7.0) 17 | activemodel (4.1.10) 18 | activesupport (= 4.1.10) 19 | builder (~> 3.1) 20 | activerecord (4.1.10) 21 | activemodel (= 4.1.10) 22 | activesupport (= 4.1.10) 23 | arel (~> 5.0.0) 24 | activesupport (4.1.10) 25 | i18n (~> 0.6, >= 0.6.9) 26 | json (~> 1.7, >= 1.7.7) 27 | minitest (~> 5.1) 28 | thread_safe (~> 0.1) 29 | tzinfo (~> 1.1) 30 | addressable (2.5.1) 31 | public_suffix (~> 2.0, >= 2.0.2) 32 | arel (5.0.1.20140414130214) 33 | ast (2.3.0) 34 | awesome_print (1.7.0) 35 | bcrypt (3.1.11) 36 | better_errors (2.1.1) 37 | coderay (>= 1.0.0) 38 | erubis (>= 2.6.6) 39 | rack (>= 0.9.0) 40 | binding_of_caller (0.7.2) 41 | debug_inspector (>= 0.0.1) 42 | brakeman (3.6.1) 43 | bugsnag (5.3.0) 44 | builder (3.2.3) 45 | bullet (5.5.1) 46 | activesupport (>= 3.0.0) 47 | uniform_notifier (~> 1.10.0) 48 | byebug (9.0.6) 49 | capybara (2.13.0) 50 | addressable 51 | mime-types (>= 1.16) 52 | nokogiri (>= 1.3.3) 53 | rack (>= 1.0.0) 54 | rack-test (>= 0.5.4) 55 | xpath (~> 2.0) 56 | chronic (0.10.2) 57 | chunky_png (1.3.8) 58 | cliver (0.3.2) 59 | coderay (1.1.1) 60 | coffee-rails (4.0.1) 61 | coffee-script (>= 2.2.0) 62 | railties (>= 4.0.0, < 5.0) 63 | coffee-script (2.4.1) 64 | coffee-script-source 65 | execjs 66 | coffee-script-source (1.12.2) 67 | compass (0.12.7) 68 | chunky_png (~> 1.2) 69 | fssm (>= 0.2.7) 70 | sass (~> 3.2.19) 71 | compass-rails (2.0.0) 72 | compass (>= 0.12.2) 73 | daemons (1.2.4) 74 | database_cleaner (1.5.3) 75 | debug_inspector (0.0.2) 76 | delorean (2.1.0) 77 | chronic 78 | devise (4.2.1) 79 | bcrypt (~> 3.0) 80 | orm_adapter (~> 0.1) 81 | railties (>= 4.1.0, < 5.1) 82 | responders 83 | warden (~> 1.2.3) 84 | diff-lcs (1.3) 85 | easy_translate (0.5.0) 86 | json 87 | thread 88 | thread_safe 89 | erb2haml (0.1.5) 90 | html2haml 91 | erubis (2.7.0) 92 | eventmachine (1.2.3) 93 | execjs (2.7.0) 94 | factory_girl (4.8.0) 95 | activesupport (>= 3.0.0) 96 | factory_girl_rails (4.8.0) 97 | factory_girl (~> 4.8.0) 98 | railties (>= 3.0.0) 99 | faker (1.7.3) 100 | i18n (~> 0.5) 101 | figaro (1.1.1) 102 | thor (~> 0.14) 103 | font-awesome-rails (4.7.0.1) 104 | railties (>= 3.2, < 5.1) 105 | fssm (0.2.10) 106 | haml (4.0.7) 107 | tilt 108 | haml-rails (0.9.0) 109 | actionpack (>= 4.0.1) 110 | activesupport (>= 4.0.1) 111 | haml (>= 4.0.6, < 5.0) 112 | html2haml (>= 1.0.1) 113 | railties (>= 4.0.1) 114 | hashie (3.5.5) 115 | highline (1.7.8) 116 | hike (1.2.3) 117 | hirb (0.7.3) 118 | hirb-unicode (0.0.5) 119 | hirb (~> 0.5) 120 | unicode-display_width (~> 0.1.1) 121 | html2haml (2.1.0) 122 | erubis (~> 2.7.0) 123 | haml (~> 4.0) 124 | nokogiri (>= 1.6.0) 125 | ruby_parser (~> 3.5) 126 | i18n (0.8.1) 127 | i18n-tasks (0.9.13) 128 | activesupport (>= 4.0.2) 129 | ast (>= 2.1.0) 130 | easy_translate (>= 0.5.0) 131 | erubis 132 | highline (>= 1.7.3) 133 | i18n 134 | parser (>= 2.2.3.0) 135 | rainbow (~> 2.2) 136 | terminal-table (>= 1.5.1) 137 | jbuilder (1.5.3) 138 | activesupport (>= 3.0.0) 139 | multi_json (>= 1.2.0) 140 | jquery-rails (3.1.4) 141 | railties (>= 3.0, < 5.0) 142 | thor (>= 0.14, < 2.0) 143 | jquery-ui-rails (6.0.1) 144 | railties (>= 3.2.16) 145 | json (1.8.6) 146 | json_expressions (0.9.0) 147 | kgio (2.11.0) 148 | launchy (2.4.3) 149 | addressable (~> 2.3) 150 | letter_opener (1.4.1) 151 | launchy (~> 2.2) 152 | mail (2.6.4) 153 | mime-types (>= 1.16, < 4) 154 | method_source (0.8.2) 155 | mime-types (3.1) 156 | mime-types-data (~> 3.2015) 157 | mime-types-data (3.2016.0521) 158 | mini_portile2 (2.1.0) 159 | minitest (5.10.1) 160 | multi_json (1.12.1) 161 | nokogiri (1.7.1) 162 | mini_portile2 (~> 2.1.0) 163 | oauth (0.5.1) 164 | omniauth (1.4.2) 165 | hashie (>= 1.2, < 4) 166 | rack (>= 1.0, < 3) 167 | omniauth-oauth (1.1.0) 168 | oauth 169 | omniauth (~> 1.0) 170 | omniauth-twitter (1.4.0) 171 | omniauth-oauth (~> 1.1) 172 | rack 173 | orm_adapter (0.5.0) 174 | parser (2.4.0.0) 175 | ast (~> 2.2) 176 | pg (0.20.0) 177 | poltergeist (1.14.0) 178 | capybara (~> 2.1) 179 | cliver (~> 0.3.1) 180 | websocket-driver (>= 0.2.0) 181 | pry (0.10.4) 182 | coderay (~> 1.1.0) 183 | method_source (~> 0.8.1) 184 | slop (~> 3.4) 185 | pry-byebug (3.4.2) 186 | byebug (~> 9.0) 187 | pry (~> 0.10) 188 | pry-doc (0.10.0) 189 | pry (~> 0.9) 190 | yard (~> 0.9) 191 | pry-rails (0.3.6) 192 | pry (>= 0.10.4) 193 | pry-stack_explorer (0.4.9.2) 194 | binding_of_caller (>= 0.7) 195 | pry (>= 0.9.11) 196 | public_suffix (2.0.5) 197 | quiet_assets (1.1.0) 198 | railties (>= 3.1, < 5.0) 199 | rack (1.5.5) 200 | rack-test (0.6.3) 201 | rack (>= 1.0) 202 | rails (4.1.10) 203 | actionmailer (= 4.1.10) 204 | actionpack (= 4.1.10) 205 | actionview (= 4.1.10) 206 | activemodel (= 4.1.10) 207 | activerecord (= 4.1.10) 208 | activesupport (= 4.1.10) 209 | bundler (>= 1.3.0, < 2.0) 210 | railties (= 4.1.10) 211 | sprockets-rails (~> 2.0) 212 | rails-db-resetup (0.0.2) 213 | railties (4.1.10) 214 | actionpack (= 4.1.10) 215 | activesupport (= 4.1.10) 216 | rake (>= 0.8.7) 217 | thor (>= 0.18.1, < 2.0) 218 | rainbow (2.2.1) 219 | raindrops (0.18.0) 220 | rake (12.0.0) 221 | rb-fsevent (0.9.8) 222 | responders (1.1.2) 223 | railties (>= 3.2, < 4.2) 224 | rspec-core (3.5.4) 225 | rspec-support (~> 3.5.0) 226 | rspec-expectations (3.5.0) 227 | diff-lcs (>= 1.2.0, < 2.0) 228 | rspec-support (~> 3.5.0) 229 | rspec-mocks (3.5.0) 230 | diff-lcs (>= 1.2.0, < 2.0) 231 | rspec-support (~> 3.5.0) 232 | rspec-rails (3.5.2) 233 | actionpack (>= 3.0) 234 | activesupport (>= 3.0) 235 | railties (>= 3.0) 236 | rspec-core (~> 3.5.0) 237 | rspec-expectations (~> 3.5.0) 238 | rspec-mocks (~> 3.5.0) 239 | rspec-support (~> 3.5.0) 240 | rspec-support (3.5.0) 241 | ruby_parser (3.8.4) 242 | sexp_processor (~> 4.1) 243 | sass (3.2.19) 244 | sass-rails (4.0.5) 245 | railties (>= 4.0.0, < 5.0) 246 | sass (~> 3.2.2) 247 | sprockets (~> 2.8, < 3.0) 248 | sprockets-rails (~> 2.0) 249 | sexp_processor (4.8.0) 250 | shoulda-matchers (3.1.1) 251 | activesupport (>= 4.0.0) 252 | slop (3.6.0) 253 | spring (1.7.2) 254 | spring-commands-rspec (1.0.4) 255 | spring (>= 0.9.1) 256 | sprockets (2.12.4) 257 | hike (~> 1.2) 258 | multi_json (~> 1.0) 259 | rack (~> 1.0) 260 | tilt (~> 1.1, != 1.3.0) 261 | sprockets-rails (2.3.3) 262 | actionpack (>= 3.0) 263 | activesupport (>= 3.0) 264 | sprockets (>= 2.8, < 4.0) 265 | sqlite3 (1.3.13) 266 | tapp (1.5.0) 267 | thor 268 | terminal-table (1.6.0) 269 | thin (1.7.0) 270 | daemons (~> 1.0, >= 1.0.9) 271 | eventmachine (~> 1.0, >= 1.0.4) 272 | rack (>= 1, < 3) 273 | thor (0.19.4) 274 | thread (0.2.2) 275 | thread_safe (0.3.6) 276 | tilt (1.4.1) 277 | tzinfo (1.2.3) 278 | thread_safe (~> 0.1) 279 | uglifier (3.2.0) 280 | execjs (>= 0.3.0, < 3) 281 | unicode-display_width (0.1.1) 282 | unicorn (5.3.0) 283 | kgio (~> 2.6) 284 | raindrops (~> 0.7) 285 | uniform_notifier (1.10.0) 286 | view_source_map (0.1.4) 287 | rails (>= 3.2) 288 | warden (1.2.7) 289 | rack (>= 1.0) 290 | websocket-driver (0.6.5) 291 | websocket-extensions (>= 0.1.0) 292 | websocket-extensions (0.1.2) 293 | xpath (2.0.0) 294 | nokogiri (~> 1.3) 295 | yard (0.9.8) 296 | 297 | PLATFORMS 298 | ruby 299 | 300 | DEPENDENCIES 301 | awesome_print 302 | better_errors 303 | binding_of_caller 304 | brakeman 305 | bugsnag 306 | bullet 307 | capybara 308 | coffee-rails (~> 4.0.0) 309 | compass-rails 310 | database_cleaner 311 | delorean 312 | devise 313 | erb2haml 314 | factory_girl 315 | factory_girl_rails 316 | faker 317 | figaro 318 | font-awesome-rails 319 | haml-rails 320 | hirb 321 | hirb-unicode 322 | i18n-tasks 323 | jbuilder (~> 1.2) 324 | jquery-rails 325 | jquery-ui-rails 326 | json_expressions 327 | launchy 328 | letter_opener 329 | nokogiri 330 | omniauth 331 | omniauth-twitter 332 | pg 333 | poltergeist 334 | pry-byebug 335 | pry-doc 336 | pry-rails 337 | pry-stack_explorer 338 | quiet_assets 339 | rails (= 4.1.10) 340 | rails-db-resetup 341 | rb-fsevent 342 | rspec-rails 343 | sass-rails (~> 4.0.0) 344 | shoulda-matchers 345 | spring 346 | spring-commands-rspec 347 | sqlite3 348 | tapp 349 | thin 350 | uglifier (>= 1.3.0) 351 | unicorn 352 | view_source_map 353 | 354 | RUBY VERSION 355 | ruby 2.3.4p301 356 | 357 | BUNDLED WITH 358 | 1.14.6 359 | -------------------------------------------------------------------------------- /Guardfile.example: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | guard 'rspec', all_on_start: false, all_after_pass: true, cmd: 'bundle exec spring rspec --color --format nested --tty' do 5 | watch(%r{^spec/.+_spec\.rb$}) 6 | watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } 7 | watch('spec/spec_helper.rb') { "spec" } 8 | 9 | # Rails example 10 | watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 11 | watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } 12 | watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/features/#{m[1]}_spec.rb"] } 13 | watch(%r{^spec/support/(.+)\.rb$}) { "spec" } 14 | watch('config/routes.rb') { "spec/routing" } 15 | watch('app/controllers/application_controller.rb') { "spec/controllers" } 16 | 17 | # Capybara features specs 18 | watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" } 19 | 20 | # Turnip features and steps 21 | watch(%r{^spec/acceptance/(.+)\.feature$}) 22 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' } 23 | end 24 | 25 | require './config/environment' 26 | 27 | guard 'sprockets2', assets_path: 'public/assets-test', digest: false do 28 | watch(%r{^app/assets/.+$}) 29 | watch('config/application.rb') 30 | end 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # K-tra! 2 | The Lightweight Task Tracker. 3 | 4 | [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) 5 | 6 | ![](https://dltvadzlmcsl3.cloudfront.net/uploads/post/image/22887/thumb_f2d084ee5288a867ac17055bc034f2cb.gif) 7 | 8 | ## Setup for development 9 | 10 | rename config/application.example.yml to config/application.yml 11 | 12 | ``` 13 | $ cp config/application.example.yml config/application.yml 14 | ``` 15 | 16 | Fill your credentials for twitter. 17 | 18 | ``` 19 | $ open https://dev.twitter.com/ 20 | ``` 21 | 22 | ``` 23 | $ open config/application.yml 24 | ``` 25 | 26 | ``` 27 | TWITTER_KEY: 'YOUR CONSUMER KEY' 28 | TWITTER_SECRET: 'YOUR CONSUMER SECRET' 29 | ``` 30 | 31 | ## Setup for test 32 | 33 | rename Guardfile.example to Guardfile 34 | 35 | ``` 36 | $ cp Guardfile.example Guardfile 37 | ``` 38 | 39 | ``` 40 | $ guard 41 | ``` 42 | 43 | ## Setup for phantom.js on Mac 44 | 45 | ``` 46 | brew update 47 | brew install phantomjs 48 | ``` 49 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Ktra::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "K-tra", 3 | "description": "The Lightweight Task Tracker", 4 | "repository": "https://github.com/taea/ktra", 5 | "logo": "https://ktra.herokuapp.com/assets/apple-touch-icon.png" 6 | } 7 | -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/assets/images/apple-touch-icon.png -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/fonts/DIN_Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/assets/images/fonts/DIN_Medium.ttf -------------------------------------------------------------------------------- /app/assets/images/ktra-header-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/assets/images/ktra-header-logo@2x.png -------------------------------------------------------------------------------- /app/assets/images/ktra.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 20 | 21 | 25 | 27 | 31 | 32 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery-ui 15 | //= require jquery_ujs 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /app/assets/javascripts/ktra.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery -> 2 | $(document).on "keypress", "input:not(.allow-submit)", (event) -> event.which != 13 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/tasks.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery -> 2 | window.Ktra ||= {} 3 | window.Ktra.tasks = new Tasks 4 | 5 | class Tasks 6 | constructor: -> 7 | @init() 8 | 9 | init: -> 10 | @listen() 11 | 12 | listen: -> 13 | @toggle_point_radio_buttons() 14 | @listen_keyup() 15 | @listen_task_point() 16 | 17 | listen_keyup: -> 18 | $(document).on 'keyup', '.new_task #task_title', @toggle_point_radio_buttons 19 | 20 | toggle_point_radio_buttons: => 21 | if $('.new_task #task_title').val() 22 | @show_point_radio_buttons() 23 | else 24 | @hide_point_radio_buttons() 25 | 26 | show_point_radio_buttons: => 27 | $(".new-task .point-radio").slideDown("fast", "swing") 28 | 29 | hide_point_radio_buttons: => 30 | $(".new-task .point-radio").hide() 31 | 32 | listen_task_point: -> 33 | $(document).on 'click', '.new_task .point-radio input', (e) => 34 | $('.new_task').submit() 35 | -------------------------------------------------------------------------------- /app/assets/javascripts/welcome.js.coffee: -------------------------------------------------------------------------------- 1 | #= require jquery 2 | #= require jquery_ujs 3 | 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css.sass: -------------------------------------------------------------------------------- 1 | @charset "utf-8" 2 | 3 | //compass 4 | @import compass/reset 5 | @import compass/utilities 6 | @import compass/css3 7 | @import font-awesome 8 | 9 | //original css 10 | @import variables 11 | @import mixin 12 | @import style 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/mixin.css.sass: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // zurui-liner-gradient 3 | // -------------------------------------------------------------------------- 4 | =gradient-top-lighten($color : #666, $lighten: 10%) 5 | background-color: $color 6 | +filter-gradient(lighten($color, $lighten), $color,vertical) 7 | +background-image(linear-gradient(lighten($color,$lighten) 0%, $color 100%)) 8 | 9 | =gradient-top-darken($color : #666, $darken: 10%) 10 | background-color: $color 11 | +filter-gradient(darken($color, $darken), $color,vertical) 12 | +background-image(linear-gradient(darken($color,$darken) 0%, $color 100%)) 13 | 14 | // ========================================================================== 15 | // alpha-gray-scale gradient 16 | // -------------------------------------------------------------------------- 17 | =gradient-gray-scale($op-fff: .1, $op-000: .1) 18 | +filter-gradient(rgba(255, 255, 255, $op-fff), rgba(0, 0, 0, $op-000),vertical) 19 | +background-image(linear-gradient(rgba(255, 255, 255, $op-fff), rgba(0, 0, 0, $op-000) 100%)) 20 | background-image: linear-gradient(rgba(255, 255, 255, $op-fff), rgba(0, 0, 0, $op-000)) 21 | 22 | // ========================================================================== 23 | // overlay 24 | // -------------------------------------------------------------------------- 25 | =op-000($op: 0.1) 26 | background-color: rgba(0,0,0,$op) 27 | 28 | =op-fff($op: 0.1) 29 | background-color: rgba(255,255,255,$op) 30 | 31 | // ========================================================================== 32 | // zurui-text-shadow 33 | // -------------------------------------------------------------------------- 34 | =ts-fff($op: 0.7) 35 | +text-shadow(rgba(255, 255, 255, $op) -1px 1px 0) 36 | 37 | =ts-000($op: 0.4) 38 | +text-shadow(rgba(0, 0, 0, $op) 1px -1px 0) 39 | 40 | =ts-fff-2x($op: 0.7) 41 | +text-shadow(rgba(255, 255, 255, $op) -2px 2px 0) 42 | 43 | =ts-000-2x($op: 0.4) 44 | +text-shadow(rgba(0, 0, 0, $op) 2px -2px 0) 45 | // ========================================================================== 46 | // zurui-box 47 | // -------------------------------------------------------------------------- 48 | =box-deboss($border: .1, $shadow: .1, $highlight: 1) 49 | border: 1px solid rgba(0,0,0,$border) 50 | +box-shadow(rgba(0, 0, 0, $shadow) -1px 1px 2px inset, rgba(255, 255, 255, $highlight) -1px 1px 0) 51 | 52 | =box-emboss($border: .15, $shadow: .05, $highlight: 1) 53 | border: 1px solid rgba(0,0,0,$border) 54 | +box-shadow(rgba(0, 0, 0, $shadow) -1px 1px 0, rgba(255, 255, 255, $highlight) -1px 1px 0 inset) 55 | 56 | =box($op: .2) 57 | +box-shadow(rgba(0, 0, 0, $op) 0 0 3px) 58 | 59 | // ========================================================================== 60 | // zurui-line 61 | // -------------------------------------------------------------------------- 62 | =line-top($op1: .75, $op2: .15) 63 | +box-shadow(rgba(255,255,255,$op1) 0 1px 0 inset) 64 | border-top: 1px solid rgba(0,0,0,$op2) 65 | 66 | =line-bottom($op1: .75, $op2: .15) 67 | +box-shadow(rgba(255,255,255,$op1) 0 2px 0) 68 | border-bottom: 2px solid rgba(0,0,0,$op2) 69 | 70 | =line-left($op1: .75, $op2: .15) 71 | +box-shadow(rgba(255,255,255,$op1) -1px 0 0) 72 | border-left: 1px solid rgba(0,0,0,$op2) 73 | 74 | =line-right($op1: .75, $op2: .15) 75 | +box-shadow(rgba(255,255,255,$op1) -1px 0 0 inset) 76 | border-right: 1px solid rgba(0,0,0,$op2) 77 | 78 | =line-top-bottom($op1: .75, $op2: .15) 79 | +box-shadow(rgba(255,255,255,$op1) 0 2px 0 inset, rgba(255,255,255,$op1) 0 2px 0) 80 | border-top: 2px solid rgba(0,0,0,$op2) 81 | border-bottom: 2px solid rgba(0,0,0,$op2) 82 | 83 | =line-left-right($op1: .75, $op2: .15) 84 | +box-shadow(rgba(255,255,255,$op1) -1px 0 0, rgba(255,255,255,$op1) -1px 0 0 inset) 85 | border-left: 1px solid rgba(0,0,0,$op2) 86 | border-right: 1px solid rgba(0,0,0,$op2) 87 | 88 | =line-top-bottom-left-right($op1: .75, $op2: .15) 89 | +box-shadow(rgba(255,255,255,$op1) -2px 0 0, rgba(255,255,255,$op1) -2px 0 0 inset, rgba(255,255,255,$op1) 0 2px 0 inset, rgba(255,255,255,$op1) 0 2px 0) 90 | border-left: 2px solid rgba(0,0,0,$op2) 91 | border-right: 2px solid rgba(0,0,0,$op2) 92 | border-top: 2px solid rgba(0,0,0,$op2) 93 | border-bottom: 2px solid rgba(0,0,0,$op2) 94 | 95 | // ========================================================================== 96 | // transform 97 | // -------------------------------------------------------------------------- 98 | =transform($deg: 6deg) 99 | -moz-transform: rotate($deg) 100 | -webkit-transform: rotate($deg) 101 | -o-transform: rotate($deg) 102 | -ms-transform: rotate($deg) 103 | transform: rotate($deg) 104 | 105 | // ========================================================================== 106 | // balloon 107 | // -------------------------------------------------------------------------- 108 | =balloon-left($size: 6px, $color: #FFF, $top: 6px) 109 | position: relative 110 | &:after 111 | position: absolute 112 | content: "" 113 | display: block 114 | border: $size solid transparent 115 | border-right: $size solid $color 116 | top: $top 117 | left: -1 * $size * 2 118 | 119 | =balloon-left-border($size: 6px, $color: #FFF, $top: 6px, $border_color: #CCC, $border: 1px) 120 | position: relative 121 | $size2 : $size + $border 122 | +balloon-left($size, $color, $top) 123 | &:before 124 | position: absolute 125 | content: "" 126 | display: block 127 | border: $size2 solid transparent 128 | border-right: $size2 solid $border_color 129 | top: $top - $border 130 | left: -1 * $size2 * 2 131 | 132 | =balloon-right($size: 6px, $color: #FFF, $top: 6px) 133 | position: relative 134 | &:after 135 | position: absolute 136 | content: "" 137 | display: block 138 | border: $size solid $color 139 | border-right: $size solid transparent 140 | border-top: $size solid transparent 141 | border-bottom: $size solid transparent 142 | top: $top 143 | right: -1 * $size * 2 144 | 145 | =balloon-right-border($size: 6px, $color: #FFF, $top: 6px, $border_color: #CCC, $border: 1px) 146 | position: relative 147 | $size2 : $size + $border 148 | +balloon-right($size, $color, $top) 149 | &:before 150 | position: absolute 151 | content: "" 152 | display: block 153 | border: $size2 solid $border_color 154 | border-right: $size2 solid transparent 155 | border-top: $size2 solid transparent 156 | border-bottom: $size2 solid transparent 157 | top: $top - $border 158 | right: -1 * $size2 * 2 159 | 160 | =balloon-top($size: 6px, $color: #FFF, $left: 6px) 161 | position: relative 162 | &:after 163 | position: absolute 164 | content: "" 165 | display: block 166 | border: $size solid $color 167 | border-top: $size solid transparent 168 | border-left: $size solid transparent 169 | border-right: $size solid transparent 170 | top: -1 * $size * 2 171 | left: $left 172 | 173 | =balloon-top-border($size: 6px, $color: #FFF, $left: 6px, $border_color: #CCC, $border: 1px) 174 | position: relative 175 | $size2 : $size + $border 176 | +balloon-top($size, $color, $left) 177 | &:before 178 | position: absolute 179 | content: "" 180 | display: block 181 | border: $size2 solid $border_color 182 | border-top: $size2 solid transparent 183 | border-left: $size2 solid transparent 184 | border-right: $size2 solid transparent 185 | top: -1 * $size2 * 2 186 | left: $left - $border 187 | 188 | =balloon-bottom($size: 6px, $color: #FFF, $left: 6px) 189 | position: relative 190 | &:after 191 | position: absolute 192 | content: "" 193 | display: block 194 | border: $size solid $color 195 | border-bottom: $size solid transparent 196 | border-left: $size solid transparent 197 | border-right: $size solid transparent 198 | bottom: -1 * $size * 2 199 | left: $left 200 | 201 | =balloon-bottom-border($size: 6px, $color: #FFF, $left: 6px, $border_color: #CCC, $border: 1px) 202 | position: relative 203 | +balloon-bottom($size, $color, $left) 204 | $size2 : $size + $border 205 | &:before 206 | position: absolute 207 | content: "" 208 | display: block 209 | border: $size2 solid $border_color 210 | border-bottom: $size2 solid transparent 211 | border-left: $size2 solid transparent 212 | border-right: $size2 solid transparent 213 | bottom: -1 * $size2 * 2 214 | left: $left - $border 215 | 216 | // ========================================================================== 217 | // font 218 | // -------------------------------------------------------------------------- 219 | @import url(//fonts.googleapis.com/css?family=Lato) 220 | @font-face 221 | font-family: 'DIN Medium' 222 | src: url('fonts/DIN_Medium.ttf') 223 | 224 | =main-font 225 | font-family: 'Lato', Arial, 'ヒラギノ角ゴPro W3','Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo , 'MS Pゴシック', sans-serif 226 | 227 | =helvetica 228 | font-family: 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif 229 | 230 | =num-font 231 | font-family: 'DIN Medium', 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif 232 | 233 | =fw-400 234 | font-weight: 400 235 | =fw-600 236 | font-weight: 600 237 | =fw-200 238 | font-weight: 200 239 | =fw-300 240 | font-weight: 300 241 | =fw-700 242 | font-weight: 700 243 | 244 | // ========================================================================== 245 | // adjustment 246 | // -------------------------------------------------------------------------- 247 | =reset 248 | margin: 0 249 | padding: 0 250 | +box-shadow(none) 251 | border: none 252 | background: none 253 | a 254 | background: none 255 | margin: 0 256 | padding: 0 257 | +box-shadow(none) 258 | border: none 259 | 260 | // ========================================================================== 261 | // misc cheat 262 | // -------------------------------------------------------------------------- 263 | =norepeat 264 | background-repeat: no-repeat 265 | 266 | =relative 267 | position: relative 268 | 269 | =absolute 270 | position: absolute 271 | 272 | =none 273 | display: none 274 | 275 | =block 276 | display: block 277 | 278 | =content 279 | content: "" 280 | display: block 281 | 282 | =nowrap 283 | overflow: hidden 284 | white-space: nowrap 285 | text-overflow: ellipsis 286 | 287 | =hidden 288 | overflow: hidden 289 | 290 | =opacity($op: .25) 291 | filter: alpha(opacity= $op * 100) 292 | -moz-opacity: $op 293 | opacity: $op 294 | 295 | =placeholder-color($color) 296 | &:-moz-placeholder 297 | color: $color 298 | &::-webkit-input-placeholder 299 | color: $color 300 | 301 | // ========================================================================== 302 | // unique design elements 303 | // -------------------------------------------------------------------------- 304 | =box-header 305 | display: block 306 | +reset 307 | +gradient-top-lighten(#EEE) 308 | border-bottom: 1px solid #DDD 309 | +box-shadow(rgba(255,255,255,1) 0 -1px inset) 310 | padding: 10px 311 | +border-top-radius(6px) 312 | +transition-duration(.3s) 313 | 314 | =box-more 315 | display: block 316 | +reset 317 | +gradient-top-darken(#FFF) 318 | border-bottom: 1px solid #DDD 319 | +box-shadow(rgba(255,255,255,1) 0 1px inset) 320 | padding: 5px 321 | +border-bottom-radius(6px) 322 | +transition-duration(.3s) 323 | text-align: center 324 | 325 | =point-in-list 326 | +absolute 327 | display: block 328 | right: 0 329 | top: 0 330 | height: 45px 331 | width: 50px 332 | padding-right: 10px 333 | text-align: right 334 | font-size: 10px 335 | span 336 | margin-right: 5px 337 | &.num 338 | margin-right: 3px 339 | +relative 340 | top: 2px 341 | +num-font 342 | font-size: 27px 343 | i 344 | color: rgba(255, 255, 255, .5) 345 | display: inline !important 346 | 347 | =list 348 | +relative 349 | border: none 350 | margin-bottom: 0 351 | >a 352 | box-sizing: border-box 353 | height: 45px 354 | line-height: 45px 355 | display: block 356 | +pie-clearfix 357 | background: $color-null 358 | color: white 359 | border-bottom: 1px solid rgba(0,0,0,.1) !important 360 | padding: 0 361 | +relative 362 | .title 363 | font-size: 14px 364 | display: block 365 | +nowrap 366 | width: $width - 60px - 60px 367 | +relative 368 | left: 60px 369 | @media only screen and (min-width : $max-device-width) 370 | width: $max-device-width - 60px - 60px 371 | .point 372 | +point-in-list 373 | 374 | =circle-button 375 | color: white 376 | background: $text-color 377 | display: block 378 | width: 60px 379 | height: 60px 380 | +border-radius(30px) 381 | font-size: 10px 382 | text-align: center 383 | border: none 384 | margin-left: 10px 385 | i 386 | font-size: 18px 387 | display: block 388 | line-height: 25px 389 | -------------------------------------------------------------------------------- /app/assets/stylesheets/style.css.sass: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | /* ktra 3 | /* -------------------------------------------------------------------------- 4 | body 5 | +main-font 6 | text-shadow: none 7 | background: desaturate(tint($base-color, 40%), 10%) 8 | padding: 0 9 | margin: 0 10 | 11 | html, body 12 | height: 100% 13 | min-height: 100% 14 | 15 | .body 16 | width: 100% 17 | min-height: 100% 18 | +relative 19 | background: $base-color 20 | padding-top: 30px 21 | @media only screen and (min-width : $max-device-width) 22 | width: $max-device-width 23 | margin: 0 auto 24 | &.welcome 25 | padding-top: 70px 26 | width: 100% 27 | text-align: center 28 | a 29 | color: white 30 | text-decoration: none 31 | 32 | .num 33 | +num-font 34 | font-size: 120% 35 | 36 | .new-task 37 | text-align: center 38 | margin: 39 | top: 20px 40 | bottom: 20px 41 | a 42 | color: white 43 | font-size: 36px 44 | 45 | input[type="submit"], button, select 46 | -webkit-appearance: none 47 | 48 | .task 49 | +list 50 | .status 51 | input[type="submit"], button 52 | +absolute 53 | box-sizing: border-box 54 | top: 0 55 | left: 0 56 | display: block 57 | width: 45px 58 | height: 45px 59 | text-align: center 60 | color: #FFF 61 | background: rgba(0, 0, 0, .1) 62 | font-size: 10px 63 | padding: 64 | left: 0 65 | right: 0 66 | top: 5px 67 | line-height: 1.5 68 | border: none !important 69 | span 70 | display: block 71 | width: 45px 72 | i 73 | font-size: 20px 74 | line-height: 20px 75 | &.fa-caret-right 76 | font-size: 24px 77 | 78 | &.unstarted 79 | a 80 | background: $color-unstarted 81 | color: $color-null 82 | .point > i 83 | color: $color-null 84 | .status > button 85 | color: white 86 | background: $color-null !important 87 | border-bottom: 1px solid (rgba(0,0,0,.1)) 88 | @for $pt from 0 through 8 89 | $pt-color: '' 90 | @if $pt == 0 91 | $pt-color: $color-pt0 92 | @else if $pt == 1 93 | $pt-color: $color-pt1 94 | @else if $pt == 2 95 | $pt-color: $color-pt2 96 | @else if $pt == 3 97 | $pt-color: $color-pt3 98 | @else if $pt == 5 99 | $pt-color: $color-pt5 100 | @else if $pt == 8 101 | $pt-color: $color-pt8 102 | @else 103 | $pt-color: $color-null 104 | &.pt#{$pt} 105 | a 106 | color: $pt-color 107 | .point > i 108 | color: $pt-color 109 | .status > input[type="submit"], button 110 | color: white 111 | background: $pt-color !important 112 | border-bottom: 1px solid (rgba(0,0,0,.1)) 113 | 114 | &.doing, &.done 115 | a 116 | background: $color-null 117 | .status > button 118 | background: rgba(255, 255, 255, .3) 119 | @for $pt from 0 through 8 120 | $pt-color: '' 121 | @if $pt == 0 122 | $pt-color: $color-pt0 123 | @else if $pt == 1 124 | $pt-color: $color-pt1 125 | @else if $pt == 2 126 | $pt-color: $color-pt2 127 | @else if $pt == 3 128 | $pt-color: $color-pt3 129 | @else if $pt == 5 130 | $pt-color: $color-pt5 131 | @else if $pt == 8 132 | $pt-color: $color-pt8 133 | @else 134 | $pt-color: $color-null 135 | &.pt#{$pt} 136 | a 137 | color: white 138 | background: $pt-color 139 | .status > input[type="submit"], button 140 | background: rgba(0, 0, 0, .1) 141 | &.done 142 | +opacity(.6) 143 | 144 | label 145 | display: block 146 | margin-bottom: 5px 147 | 148 | input, select, textarea 149 | outline: none 150 | 151 | input[type="text"], textarea 152 | width: 280px - 20px 153 | background: $text-color 154 | padding: 10px 155 | right: 30px 156 | border: none 157 | color: $white 158 | +border-radius(4px) 159 | font-size: 12px 160 | +transition-duration(.3s) 161 | +placeholder-color(rgba(0,0,0,.2)) 162 | &:focus 163 | background: $text-color 164 | color: white 165 | padding-right: 10px 166 | width: 280px 167 | &.task-title 168 | font-size: 14px 169 | &.memo 170 | height: 100px 171 | 172 | select 173 | font-size: 16px 174 | color: #FFF 175 | background: $text-color 176 | border: 1px solid $color-unstarted 177 | padding: 5px 178 | +border-left-radius(4px) 179 | +transition-duration(.3s) 180 | &:focus 181 | background: $text-color 182 | color: white 183 | 184 | .actions 185 | width: 100px 186 | margin: 0 auto 187 | i 188 | display: block 189 | width: 100% 190 | font-size: 30px 191 | text-align: center 192 | margin-bottom: 10px 193 | input[type="submit"], button 194 | color: white 195 | background: $text-color 196 | width: 70px 197 | height: 70px 198 | +border-radius(35px) 199 | font-size: 10px 200 | text-align: center 201 | border: none 202 | margin-left: 10px 203 | display: block 204 | line-height: 1 205 | +relative 206 | left: 5px 207 | i 208 | font-size: 24px 209 | display: block 210 | line-height: 20px 211 | +relative 212 | top: 2px 213 | 214 | 215 | .edit 216 | background: $color-unstarted 217 | color: $text-color 218 | padding: 10px 0 30px 219 | overflow: hidden 220 | +none 221 | border-bottom: 1px solid rgba(0,0,0,.05) 222 | 223 | .fa-pencil 224 | color: rgba(0,0,0,.2) 225 | +relative 226 | left: -25px 227 | top: 2px 228 | 229 | .sub-action 230 | line-height: 20px 231 | margin: 232 | top: 10px 233 | +clearfix 234 | li 235 | float: left 236 | a 237 | color: $text-color 238 | font-size: 10px 239 | i 240 | font-size: 20px 241 | +relative 242 | top: 3px 243 | button 244 | background: transparent !important 245 | border: none 246 | color: white !important 247 | +relative 248 | top: 2px 249 | i 250 | margin-right: 5px 251 | font-size: 120% 252 | 253 | .tweet 254 | margin-top: 20px 255 | text-align: center 256 | a 257 | i 258 | font-size: 130% 259 | color: rgba(white, .5) 260 | +relative 261 | top: 2px 262 | 263 | .time 264 | font-size: 10px 265 | margin-top: 30px 266 | dl 267 | +clearfix 268 | dt, dd 269 | float: left 270 | margin-right: 5px 271 | dd 272 | margin-right: 10px 273 | 274 | .form-header 275 | +pie-clearfix 276 | margin-bottom: 20px 277 | h2 278 | float: left 279 | width: 120px 280 | text-align: right 281 | +fw-300 282 | font-size: 18px 283 | line-height: 60px 284 | button 285 | +circle-button 286 | float: left 287 | @for $pt from 0 through 8 288 | $pt-color: '' 289 | @if $pt == 0 290 | $pt-color: $color-pt0 291 | @else if $pt == 1 292 | $pt-color: $color-pt1 293 | @else if $pt == 2 294 | $pt-color: $color-pt2 295 | @else if $pt == 3 296 | $pt-color: $color-pt3 297 | @else if $pt == 5 298 | $pt-color: $color-pt5 299 | @else if $pt == 8 300 | $pt-color: $color-pt8 301 | @else 302 | $pt-color: $text-color 303 | &.pt#{$pt} 304 | color: $pt-color 305 | input[type="text"], select, textarea 306 | background: $pt-color 307 | color: white 308 | &:focus 309 | background: $zurui-gray 310 | color: $pt-color 311 | input[type="submit"], button 312 | background: $pt-color 313 | color: white 314 | .destroy > a 315 | color: $pt-color 316 | .tweet > a 317 | color: $pt-color 318 | i 319 | color: rgba($pt-color, .5) 320 | 321 | &.doing, &.done 322 | .destroy > a 323 | color: white 324 | @for $pt from 0 through 8 325 | $pt-color: '' 326 | @if $pt == 0 327 | $pt-color: $color-pt0 328 | @else if $pt == 1 329 | $pt-color: $color-pt1 330 | @else if $pt == 2 331 | $pt-color: $color-pt2 332 | @else if $pt == 3 333 | $pt-color: $color-pt3 334 | @else if $pt == 5 335 | $pt-color: $color-pt5 336 | @else if $pt == 8 337 | $pt-color: $color-pt8 338 | @else 339 | $pt-color: $text-color 340 | &.pt#{$pt} 341 | background: $pt-color 342 | color: white 343 | input[type="text"], select, textarea 344 | background: rgba(0,0,0,.1) 345 | color: white 346 | &:focus 347 | background: white 348 | color: $pt-color 349 | select 350 | border: darken($pt-color, 10%) 351 | &:focus 352 | border: darken($pt-color, 10%) 353 | input[type="submit"], button 354 | background: white 355 | color: $pt-color 356 | .destroy > a 357 | color: white 358 | .tweet > a 359 | color: white 360 | i 361 | color: rgba(white, .5) 362 | 363 | .form 364 | width: 320px 365 | margin: 0 auto 366 | padding: 20px 10px 367 | top: 0 368 | overflow: hidden 369 | 370 | .field 371 | +pie-clearfix 372 | margin-bottom: 20px 373 | &.point-radio 374 | ul 375 | +pie-clearfix 376 | +relative 377 | left: 0 378 | margin-left: 10px 379 | li 380 | float: left 381 | +relative 382 | left: 0 383 | margin-right: 5px 384 | &.point-radio-text 385 | font-size: 10px 386 | line-height: 40px 387 | display: inline 388 | &:first-child 389 | position: relative 390 | left: 0 391 | &:last-child 392 | position: relative 393 | left: 0 394 | input 395 | display: none 396 | label 397 | display: inline-block 398 | background: white 399 | color: $text-color 400 | width: 40px 401 | height: 40px 402 | +border-radius(22px) 403 | +relative 404 | left: 0px 405 | text-align: center 406 | font-size: 10px 407 | border: 1px solid rgba(0,0,0,.05) 408 | .num 409 | display: block 410 | font-size: 24px 411 | line-height: 24px 412 | +relative 413 | top: 5px 414 | &:hover 415 | cursor: pointer 416 | input:checked+label 417 | background: $text-color 418 | color: white 419 | 420 | @for $pt from 1 through 8 421 | $pt-color: '' 422 | @if $pt == 1 423 | $pt-color: $color-pt1 424 | @else if $pt == 2 425 | $pt-color: $color-pt2 426 | @else if $pt == 3 427 | $pt-color: $color-pt3 428 | @else if $pt == 5 429 | $pt-color: $color-pt5 430 | @else if $pt == 8 431 | $pt-color: $color-pt8 432 | @else 433 | $pt-color: $text-color 434 | &.pt#{$pt} 435 | label 436 | color: $pt-color 437 | input:checked+label 438 | background: $pt-color 439 | color: white 440 | 441 | .new-task 442 | text-align: left 443 | padding: 0 444 | input[type="text"] 445 | background: rgba(0,0,0,.1) 446 | +placeholder-color(rgba(0,0,0,.2)) 447 | +relative 448 | left: 10px 449 | &:focus 450 | +placeholder-color(rgba(0,0,0,.2)) 451 | color: $text-color 452 | background: white 453 | .fa-pencil 454 | color: rgba(0,0,0,.2) 455 | +relative 456 | left: -15px 457 | top: 2px 458 | .point-radio 459 | +relative 460 | left: 12px 461 | margin-bottom: 5px 462 | .point-radio-text 463 | color: white 464 | .actions 465 | i.fa-arrow-down 466 | color: white 467 | font-size: 30px 468 | +relative 469 | left: -3px 470 | margin-bottom: 0 471 | button 472 | background: none 473 | width: 40px 474 | height: 40px 475 | +border-radius(none) 476 | text-align:center 477 | +relative 478 | top: 0 479 | left: -6px 480 | margin: 0 auto 481 | bottom: 20px 482 | i 483 | font-size: 40px 484 | line-height: 40px 485 | 486 | .header 487 | width: 300px 488 | margin: 0 auto 15px 489 | padding: 0 10px 490 | +clearfix 491 | h1 > a 492 | display: block 493 | +num-font 494 | font-size: 25px 495 | padding-left: 45px 496 | background: url(ktra-header-logo@2x.png) no-repeat left 7px 497 | background-size: 45px 33px 498 | height: 40px 499 | line-height: 62px 500 | width: 70px 501 | float: left 502 | &:hover 503 | +opacity(.9) 504 | 505 | .user 506 | float: right 507 | +clearfix 508 | +relative 509 | top: 10px 510 | p 511 | float: right 512 | margin-left: 5px 513 | font-size: 10px 514 | line-height: 30px 515 | &:hover 516 | +opacity(.8) 517 | &.image 518 | img 519 | width: 30px 520 | height: 30px 521 | +border-radius(30px) 522 | 523 | .week-summary 524 | color: white 525 | +pie-clearfix 526 | width: $width - 20px 527 | margin: 10px auto 528 | top: 20px 529 | padding: 0 10px 530 | +relative 531 | .date 532 | float: left 533 | ul 534 | margin-right: 5px 535 | float: left 536 | +pie-clearfix 537 | li 538 | float: left 539 | &.year, &.month 540 | +relative 541 | top: 5px 542 | font-size: 15px 543 | padding-right: 5px 544 | border-right: 1px solid rgba(white, .5) 545 | margin-right: 5px 546 | line-height: 15px 547 | padding-top: 2px 548 | height: 13px 549 | &.day 550 | font-size: 26px 551 | i 552 | float: left 553 | margin-right: 5px 554 | line-height: 26px 555 | color: rgba(white, .5) 556 | &.fa-chevron-right 557 | font-size: 11px 558 | &.fa-calendar 559 | font-size: 18px 560 | 561 | .right 562 | float: right 563 | +pie-clearfix 564 | .total-points 565 | +relative 566 | top: -4px 567 | +border-radius(4px) 568 | +balloon-bottom($color: white, $left: 28px) 569 | float: left 570 | background: white 571 | padding: 3px 8px 572 | top: 4px 573 | width: 50px 574 | color: $text-color 575 | font-size: 10px 576 | text-align: right 577 | .num 578 | font-size: 20px 579 | +relative 580 | top: 2px 581 | margin-right: 2px 582 | i 583 | margin-right: 2px 584 | color: rgba($text-color, .5) 585 | .fa-angle-right 586 | font-size: 20px 587 | color: rgba(white, .5) 588 | float: right 589 | margin-left: 3px 590 | 591 | .week 592 | +list 593 | .week-summary 594 | width: 100% 595 | margin: 0 596 | .date 597 | +relative 598 | top: 2px 599 | .year, .month 600 | top: 15px 601 | i 602 | +relative 603 | top: 10px 604 | .total-points 605 | +point-in-list 606 | right: 20px 607 | color: white 608 | background: none 609 | top: -5px 610 | text-align: right 611 | width: 100px 612 | .num 613 | font-size: 24px 614 | &:after 615 | display: none 616 | 617 | .error-message 618 | padding: 50px 0 619 | color: rgba(white, .5) 620 | text-align: center 621 | 622 | .footer 623 | padding: 30px 0 624 | text-align: center 625 | font-size: 10px 626 | color: rgba(255, 255, 255, .8) 627 | line-height: 1.4 628 | a 629 | color: white 630 | 631 | .footer-nav 632 | margin-bottom: 10px 633 | ul 634 | +pie-clearfix 635 | margin: 0 auto 636 | text-align: center 637 | display: inline-block 638 | li 639 | float: left 640 | a 641 | i 642 | font-size: 120% 643 | color: rgba(white, .5) 644 | +relative 645 | top: 1px 646 | 647 | .footer-repository 648 | font-size: 24px 649 | margin-top: 20px 650 | a 651 | color: rgba(0,0,0,.1) 652 | 653 | .welcome 654 | color: white 655 | .ktra-image 656 | margin-bottom: 15px 657 | .logo 658 | +num-font 659 | font-size: 40px 660 | .catch 661 | margin-bottom: 30px 662 | font-size: 16px 663 | .sign-in 664 | +circle-button 665 | margin: 0 auto 30px 666 | float: none 667 | background: $color-pt1 668 | i 669 | font-size: 30px 670 | +relative 671 | top: 5px 672 | line-height: 35px 673 | span 674 | +relative 675 | top: 2px 676 | -------------------------------------------------------------------------------- /app/assets/stylesheets/variables.css.sass: -------------------------------------------------------------------------------- 1 | $main-color: #3b97d3 2 | $sub-color: #E0663B 3 | $text-color: #888 4 | $accent-color: #E99012 5 | $base-color: #dbbea1 6 | 7 | $link-color: $main-color 8 | $hover-color: darken($main-color, 10%) 9 | $white: #FFF 10 | $zurui-gray: #E6E6E6 11 | $line-color: #ddd 12 | $light-yellow: #f3f3cc 13 | $color-pt1: lighten(adjust-hue(desaturate(#3b97d3, 10%), 7), 4%) 14 | $color-pt2: desaturate(#25b89a, 10%) 15 | $color-pt3: desaturate(darken(#efc319, 3%), 10%) 16 | $color-pt5: desaturate(#e57d24, 10%) 17 | $color-pt8: desaturate(#d35400, 10%) 18 | $color-null: #AAA 19 | $color-pt0: $color-null 20 | $color-unstarted: $white 21 | $color-done: #666 22 | 23 | $width: 320px 24 | $max-device-width: 750px 25 | -------------------------------------------------------------------------------- /app/controllers/accounts_controller.rb: -------------------------------------------------------------------------------- 1 | class AccountsController < ApplicationController 2 | before_action :authenticate_user! 3 | respond_to :json 4 | 5 | def show 6 | @user = current_user 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | def twitter 3 | @user = User.authentication(auth_hash, current_user) 4 | sign_in(@user) 5 | redirect_to root_path, notice: t('devise.omniauth_callbacks.success', kind: :twitter) 6 | end 7 | 8 | def failure 9 | redirect_to root_path, notice: 'OAuth Failure' 10 | end 11 | 12 | protected 13 | 14 | def auth_hash 15 | request.env['omniauth.auth'] 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/controllers/statuses_controller.rb: -------------------------------------------------------------------------------- 1 | class StatusesController < ApplicationController 2 | before_action :set_task 3 | respond_to :js 4 | 5 | def update 6 | @task.update_attributes(status_param) 7 | @this_week = Week.current 8 | end 9 | 10 | private 11 | 12 | def set_task 13 | @task = current_user.tasks.find(params[:task_id]) 14 | end 15 | 16 | def status_param 17 | params.require(:task).permit(:status, :week_id) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/tasks_controller.rb: -------------------------------------------------------------------------------- 1 | class TasksController < ApplicationController 2 | before_action :authenticate_user!, except: [:index] 3 | before_action :set_task, only: [:show, :edit, :update, :destroy] 4 | respond_to :html, :json 5 | 6 | # GET /tasks 7 | # GET /tasks.json 8 | def index 9 | @tasks = current_user.tasks.active if user_signed_in? 10 | @task = Task.new 11 | @this_week = Week.current 12 | respond_to do |format| 13 | format.html # index.html.erb 14 | format.json { render json: @tasks } 15 | end 16 | end 17 | 18 | # GET /tasks/1/edit 19 | def edit 20 | @this_week = Week.current 21 | respond_with @task do |f| 22 | f.js { render } 23 | f.html { redirect_to root_path } 24 | end 25 | end 26 | 27 | # POST /tasks 28 | # POST /tasks.json 29 | def create 30 | @task = Task.new(task_param) 31 | @task.user_id = current_user.id 32 | 33 | respond_to do |format| 34 | if @task.save 35 | format.json { render json: @task, status: :created, location: @task } 36 | format.js { render } 37 | else 38 | format.json { render json: @task.errors, status: :unprocessable_entity } 39 | end 40 | end 41 | end 42 | 43 | def show 44 | respond_with @task 45 | end 46 | 47 | # PUT /tasks/1 48 | # PUT /tasks/1.json 49 | def update 50 | respond_to do |format| 51 | if @task.update_attributes(task_param) 52 | format.json { head :no_content } 53 | format.js { render } 54 | else 55 | format.json { render json: @task.errors, status: :unprocessable_entity } 56 | end 57 | end 58 | end 59 | 60 | # DELETE /tasks/1 61 | # DELETE /tasks/1.json 62 | def destroy 63 | @task.destroy 64 | 65 | respond_to do |format| 66 | format.json { head :no_content } 67 | format.js { render } 68 | end 69 | end 70 | 71 | private 72 | 73 | def set_task 74 | @task = current_user.tasks.find(params[:id]) 75 | end 76 | 77 | def task_param 78 | params. 79 | require(:task). 80 | permit(:finished_at, :memo, :point, :started_at, :title, :week_id) 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /app/controllers/weeks_controller.rb: -------------------------------------------------------------------------------- 1 | class WeeksController < ApplicationController 2 | before_action :authenticate_user! 3 | before_action :set_week, only: [:show] 4 | respond_to :html, :json 5 | 6 | def index 7 | @weeks = Week.since_first_task_by(current_user).order('start_date DESC') 8 | respond_with @weeks 9 | end 10 | 11 | def show 12 | @tasks = @week.tasks.owned_by(current_user) 13 | 14 | respond_to do |format| 15 | format.html # show.html.erb 16 | format.json { render json: @week } 17 | end 18 | end 19 | 20 | private 21 | 22 | def set_week 23 | @week = Week.find(params[:id]) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | def index 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/tasks_helper.rb: -------------------------------------------------------------------------------- 1 | module TasksHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/task.rb: -------------------------------------------------------------------------------- 1 | class Task < ActiveRecord::Base 2 | POINTS = %w(0 1 2 3 5 8) 3 | validates_presence_of :user_id, :title, :status 4 | validates_inclusion_of :status, in: %w(unstarted doing done) 5 | belongs_to :user 6 | scope :active, -> { where(status: ['unstarted', 'doing']).order("status ASC, updated_at DESC") } 7 | scope :owned_by, -> (user) { where(user_id: user ) } 8 | 9 | before_validation :set_default_status 10 | 11 | def set_default_status 12 | self.status = 'unstarted' unless self.status 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | devise :omniauthable 3 | #attr_accessible :image, :name, :nickname, :secret, :token, :uid 4 | has_many :tasks, dependent: :destroy 5 | 6 | validates_presence_of :uid 7 | validates_uniqueness_of :uid 8 | 9 | def self.authentication(auth, current_user) 10 | begin 11 | params = { 12 | uid: auth['uid'], 13 | name: auth['info']['name'], 14 | nickname: auth['info']['nickname'], 15 | image: auth['info']['image'], 16 | token: auth['credentials']['token'], 17 | secret: auth['credentials']['secret'], 18 | } 19 | rescue => e 20 | return nil 21 | end 22 | 23 | user = User.where(uid: params[:uid]).first_or_initialize 24 | user.attributes = params 25 | user.save 26 | user 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/week.rb: -------------------------------------------------------------------------------- 1 | class Week < ActiveRecord::Base 2 | #attr_accessible :end_date, :start_date 3 | has_many :tasks 4 | 5 | scope :since_first_task_by, -> (user) { 6 | first_task_created_at = user.tasks.first.try(:created_at) 7 | return where('1 = 0') unless first_task_created_at 8 | where('end_date >= ?', first_task_created_at.to_date) 9 | } 10 | 11 | def self.current(time = Time.current) 12 | self.where(start_date: time.in_time_zone.beginning_of_week.to_date) 13 | .where(end_date: time.in_time_zone.end_of_week.to_date) 14 | .first_or_create! 15 | end 16 | 17 | def total_point(current_user) 18 | self.tasks.owned_by(current_user).sum(:point) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/views/accounts/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.user do 2 | json.extract! @user, :uid, :name, :nickname, :image 3 | end 4 | -------------------------------------------------------------------------------- /app/views/application/_footer.html.haml: -------------------------------------------------------------------------------- 1 | %footer.footer 2 | - if user_signed_in? 3 | .footer-nav 4 | %ul 5 | %li 6 | = link_to user_session_path, method: :delete do 7 | %i.fa.fa-sign-out 8 | = 'Sign out' 9 | %small 10 | Created by 11 | =link_to '@ken_c_lo', 'https://twitter.com/ken_c_lo', target: '_blank' 12 |   13 | =link_to '@katton', 'https://twitter.com/katton', target: '_blank' 14 |   15 | =link_to '@ppworks', 'https://twitter.com/ppworks', target: '_blank' 16 |   17 | =link_to '@fukayatsu', 'https://twitter.com/fukayatsu', target: '_blank' 18 | %br 19 | Thanks 20 | =link_to '#p4d', 'http://prog4designer.github.io/', target: '_blank' 21 | %br 22 | =link_to 'CC BY-NC-SA 2.1', 'http://creativecommons.org/licenses/by-nc-sa/2.1/jp/', target: '_blank' 23 |   24 | = "/" 25 |   26 | =link_to 'https://github.com/taea/ktra', target: '_blank', title: 'Fork me!' do 27 | Fork me on 28 |   29 | %strong<> GitHub 30 | -------------------------------------------------------------------------------- /app/views/application/_ga.html.haml: -------------------------------------------------------------------------------- 1 | :javascript 2 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 3 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 4 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 5 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); 6 | 7 | ga('create', 'UA-49960821-1', 'ktra.herokuapp.com'); 8 | ga('send', 'pageview'); 9 | -------------------------------------------------------------------------------- /app/views/application/_head.html.haml: -------------------------------------------------------------------------------- 1 | %head 2 | %title K-tra! The Lightweight Task Tracker 3 | = stylesheet_link_tag "application", :media => "all" 4 | = csrf_meta_tags 5 | %meta(name='viewport' content= "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no")/ 6 | %meta(name='format-detection' content= "telephone=no")/ 7 | %meta(name='apple-mobile-web-app-capable' content= "no")/ 8 | %meta(name='apple-mobile-web-app-status-bar-style' content= "black-translucent")/ 9 | %meta(name='description' content= "")/ 10 | %meta(name='keywords' content= "")/ 11 | %meta(property='og:title' content= "K-tra! The Lightwaight Task Tracker")/ 12 | %meta(property='og:url' content= "")/ 13 | %meta(property='og:type' content= "")/ 14 | %meta(property='og:site_name' content= "ktra")/ 15 | = favicon_link_tag 'apple-touch-icon.png', rel: 'apple-touch-icon', type: 'image/png' 16 | = favicon_link_tag 17 | = render ('ga') 18 | -------------------------------------------------------------------------------- /app/views/application/_header.html.haml: -------------------------------------------------------------------------------- 1 | %header.header 2 | %h1= link_to "K-tra!", root_path 3 | .user 4 | - if current_user 5 | %p.image 6 | =link_to image_tag(current_user.image), weeks_path 7 | %p.name 8 | = link_to current_user.nickname, weeks_path 9 | - else 10 | %p.name 11 | = link_to '/users/auth/twitter' do 12 | sign in 13 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | = render ('head') 4 | = javascript_include_tag "application" 5 | %body 6 | .body 7 | = render ('header') 8 | = yield 9 | = render ('footer') 10 | -------------------------------------------------------------------------------- /app/views/layouts/welcome.html.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | = render ('head') 4 | = javascript_include_tag "welcome" 5 | %body 6 | .body.welcome 7 | = yield 8 | = render ('footer') 9 | -------------------------------------------------------------------------------- /app/views/statuses/update.js.erb: -------------------------------------------------------------------------------- 1 | var target = '#task<%= @task.id %>'; 2 | <% if @task.status == 'done' %> 3 | $(target).hide('blind', 400, function(){ 4 | $(target).remove(); 5 | }); 6 | <% else %> 7 | $(target).replaceWith('<%=j render(partial: 'tasks/task', locals: {task: @task}) %>'); 8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/tasks/_edit.html.haml: -------------------------------------------------------------------------------- 1 | .edit{class: "#{task.status} pt#{task.point}"} 2 | .form 3 | = render 'form', task: task 4 | .tweet 5 | - status_text = task.status == 'unstarted' ? 'TODO' : task.status.upcase 6 | = link_to "http://twitter.com/share?text=#{status_text}: #{task.title} [#{task.point}pt] @ktra_app&url=https://ktra.herokuapp.com", target: '_blank' do 7 | %i.fa.fa-twitter 8 | Tweet this task 9 | .time 10 | %dl 11 | %dt START 12 | - if task.started_at 13 | %dd.num= task.started_at.to_s(:db) 14 | - else 15 | %dd= '---' 16 | %dt FINISH 17 | - if task.finished_at 18 | %dd.num= task.finished_at.to_s(:db) 19 | - else 20 | %dd= '---' 21 | %ul.sub-action 22 | %li 23 | = link_to task_path(task), method: 'delete', remote: true, confirm: 'Are you sure you want to delete this task?' do 24 | %i.fa.fa-times-circle 25 | DELETE 26 | - if task.status == 'doing' 27 | %li= render 'tasks/form/stop', task: task 28 | -------------------------------------------------------------------------------- /app/views/tasks/_form.html.haml: -------------------------------------------------------------------------------- 1 | = form_for task, remote: true do |f| 2 | - if task.errors.any? 3 | #error_explanation 4 | %h2 5 | = pluralize(task.errors.count, "error") 6 | prohibited this task from being saved: 7 | %ul 8 | - task.errors.full_messages.each do |msg| 9 | %li= msg 10 | .field 11 | = render ('tasks/form/title'), f: f, placeholder: 'TITLE' 12 | .field.point-radio 13 | = render partial: 'tasks/form/points', locals: {f: f, edit: "_#{task.id}"} 14 | .field 15 | = f.text_area :memo, class: 'memo', placeholder: 'MEMO' 16 | .actions 17 | %i.fa.fa-arrow-down 18 | = f.button "#{content_tag(:i, '', class: 'fa fa-floppy-o')}SAVE".html_safe, type: :submit 19 | -------------------------------------------------------------------------------- /app/views/tasks/_task.html.haml: -------------------------------------------------------------------------------- 1 | %li.task{id: "task#{task.id}", class: "#{task.status} pt#{task.point}"} 2 | =link_to edit_task_path(task), remote: true do 3 | %span.title<>= task.title 4 | - if task.point.present? 5 | %span.point<> 6 | %span.num<>= task.point 7 | pt 8 | %i.fa.fa-chevron-right 9 | - else 10 | %span.point<> 11 | %span<>= '─' 12 | pt 13 | %i.fa.fa-chevron-right 14 | = render ("tasks/task/#{task.status}"), task: task 15 | -------------------------------------------------------------------------------- /app/views/tasks/_tasks.html.haml: -------------------------------------------------------------------------------- 1 | %ul.tasks-list 2 | - @tasks.each do |task| 3 | = render 'tasks/task', task: task 4 | -------------------------------------------------------------------------------- /app/views/tasks/create.js.erb: -------------------------------------------------------------------------------- 1 | if($('.tasks-list').length){ 2 | } else { 3 | $('.error-message').remove(); 4 | $('.week-summary').after(""); 5 | } 6 | 7 | $('.tasks-list').prepend('<%=j render(partial: 'task', locals: { task: @task }) %>'); 8 | $('.new-task #task_title').val(''); 9 | $('.point-radio input').prop('checked', false); 10 | Ktra.tasks.toggle_point_radio_buttons(); 11 | -------------------------------------------------------------------------------- /app/views/tasks/destroy.js.erb: -------------------------------------------------------------------------------- 1 | var target = '#task<%= @task.id %>'; 2 | $(target).hide('blind', 400, function(){ 3 | $(target).remove(); 4 | }); 5 | -------------------------------------------------------------------------------- /app/views/tasks/edit.js.erb: -------------------------------------------------------------------------------- 1 | var target = '#task<%= @task.id %>'; 2 | var targetEdit = '#task<%= @task.id %> .edit'; 3 | 4 | if($(targetEdit).length){ 5 | $(targetEdit).hide('blind', 400); 6 | $(targetEdit).promise().done(function(){ 7 | $(targetEdit).remove(); 8 | }); 9 | } else { 10 | $(target).append('<%=j render(partial: 'edit', locals: {task: @task}) %>'); 11 | $(target).promise().done(function(){ 12 | $(targetEdit).show('blind', 400); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /app/views/tasks/form/_done.html.haml: -------------------------------------------------------------------------------- 1 | = form_for(task, remote: true, url: task_status_path(task)) do |f| 2 | = f.hidden_field :finished_at, value: Time.now.to_s(:db) 3 | = f.hidden_field :status, value: 'done' 4 | = f.hidden_field :week_id, value: @this_week.id 5 | = f.button "#{content_tag(:i, '', class: 'fa fa-check-circle')}DONE".html_safe, type: :submit 6 | -------------------------------------------------------------------------------- /app/views/tasks/form/_points.html.haml: -------------------------------------------------------------------------------- 1 | %ul 2 | - Task::POINTS.each do |pt| 3 | %li{class: "pt#{pt}"} 4 | = f.radio_button :point, pt, id: "task_point_#{pt + edit}" 5 | = f.label :point, for: "task_point_#{pt + edit}" do 6 | %span.num<>= pt 7 | pt 8 | -------------------------------------------------------------------------------- /app/views/tasks/form/_restart.html.haml: -------------------------------------------------------------------------------- 1 | = form_for(task, remote: true, url: task_status_path(task)) do |f| 2 | = f.hidden_field :started_at, value: Time.now.to_s(:db) 3 | = f.hidden_field :status, value: 'doing' 4 | = f.hidden_field :week_id, value: nil 5 | = f.button "#{content_tag(:i, '', class: 'fa fa-repeat')}RESTART".html_safe, type: :submit 6 | -------------------------------------------------------------------------------- /app/views/tasks/form/_start.html.haml: -------------------------------------------------------------------------------- 1 | = form_for(task, remote: true, url: task_status_path(task)) do |f| 2 | = f.hidden_field :started_at, value: Time.now.to_s(:db) 3 | = f.hidden_field :status, value: 'doing' 4 | = f.hidden_field :week_id, value: nil 5 | = f.button " #{content_tag(:i, '', class: 'fa fa-play-circle')}START".html_safe, type: :submit 6 | -------------------------------------------------------------------------------- /app/views/tasks/form/_stop.html.haml: -------------------------------------------------------------------------------- 1 | = form_for(task, remote: true, url: task_status_path(task)) do |f| 2 | = f.hidden_field :status, value: 'unstarted' 3 | = f.hidden_field :week_id, value: nil 4 | = f.button "#{content_tag(:i, '', class: 'fa fa-pause')}STOP".html_safe, type: :submit 5 | -------------------------------------------------------------------------------- /app/views/tasks/form/_title.html.haml: -------------------------------------------------------------------------------- 1 | = f.text_field :title, class: 'task-title', autocomplete: 'off', placeholder: placeholder, required: true, class: "#{'allow-submit' unless local_assigns[:new_task]}" 2 | %i.fa.fa-pencil 3 | -------------------------------------------------------------------------------- /app/views/tasks/index.html.haml: -------------------------------------------------------------------------------- 1 | - if user_signed_in? 2 | .form.new-task 3 | = form_for(@task, remote: true) do |f| 4 | - if @task.errors.any? 5 | #error_explanation 6 | %h2 7 | = pluralize(@task.errors.count, "error") 8 | prohibited this task from being saved: 9 | %ul 10 | - @task.errors.full_messages.each do |msg| 11 | %li= msg 12 | .field 13 | = render ('tasks/form/title'), f: f, placeholder: 'NEW TASK TITLE', new_task: true 14 | .field.point-radio 15 | = render partial: 'tasks/form/points', locals: {f: f, edit: ''} 16 | - else 17 | - # FIXME 18 | = link_to '/users/auth/twitter' do 19 | Sign in with Twitter 20 | 21 | .week-summary 22 | = link_to week_path(@this_week) do 23 | = render 'weeks/summary', week: @this_week, tasks: true 24 | 25 | - if user_signed_in? && @tasks.present? 26 | = render 'tasks' 27 | - else 28 | %p.error-message There's no tasks yet. 29 | -------------------------------------------------------------------------------- /app/views/tasks/statuses/_doing.html.haml: -------------------------------------------------------------------------------- 1 | %h2 2 | DOING 3 | %i.fa.fa-arrow-right 4 | = render ('tasks/form/done'), task: @task 5 | = render ('tasks/form/stop'), task: @task 6 | -------------------------------------------------------------------------------- /app/views/tasks/statuses/_done.html.haml: -------------------------------------------------------------------------------- 1 | %h2 2 | DONE 3 | %i.fa.fa-arrow-right 4 | = render ('tasks/form/restart'), task: @task 5 | -------------------------------------------------------------------------------- /app/views/tasks/statuses/_unstarted.html.haml: -------------------------------------------------------------------------------- 1 | %h2 2 | STANDBY 3 | %i.fa.fa-arrow-right 4 | = render ('tasks/form/start'), task: @task 5 | -------------------------------------------------------------------------------- /app/views/tasks/task/_doing.html.haml: -------------------------------------------------------------------------------- 1 | %span.status<> 2 | = render ('tasks/form/done'), task: task 3 | -------------------------------------------------------------------------------- /app/views/tasks/task/_done.html.haml: -------------------------------------------------------------------------------- 1 | %span.status<> 2 | = render ('tasks/form/restart'), task: task 3 | -------------------------------------------------------------------------------- /app/views/tasks/task/_unstarted.html.haml: -------------------------------------------------------------------------------- 1 | %span.status<> 2 | = render ('tasks/form/start'), task: task 3 | -------------------------------------------------------------------------------- /app/views/tasks/update.js.erb: -------------------------------------------------------------------------------- 1 | var target = '#task<%= @task.id %>'; 2 | var targetEdit = '#task<%= @task.id %> .edit'; 3 | 4 | $(targetEdit).hide('blind', 400, function(){ 5 | $(target).replaceWith('<%=j render(partial: 'task', locals: {task: @task}) %>'); 6 | }); 7 | -------------------------------------------------------------------------------- /app/views/weeks/_summary.html.haml: -------------------------------------------------------------------------------- 1 | .date 2 | - unless local_assigns[:weeks] 3 | %i.fa.fa-calendar 4 | %ul.start-date 5 | %li.year.num= "#{week.start_date.year}" 6 | %li.month.num= "#{p sprintf("%0#2d", week.start_date.month)}" 7 | %li.day.num= p sprintf("%0#2d", week.start_date.day) 8 | %i.fa.fa-arrow-right 9 | %ul.end-date 10 | %li.month.num= "#{p sprintf("%0#2d", week.end_date.month)}" 11 | %li.day.num= p sprintf("%0#2d", week.end_date.day) 12 | - if local_assigns[:tasks] 13 | %i.fa.fa-chevron-right 14 | .right 15 | .total-points 16 | %i.fa.fa-check 17 | %span.num<> 18 | = week.total_point(current_user) 19 | pt 20 | - if local_assigns[:weeks] 21 | %i.fa.fa-chevron-right 22 | -------------------------------------------------------------------------------- /app/views/weeks/index.html.haml: -------------------------------------------------------------------------------- 1 | %ul.weeks-list 2 | - @weeks.each do |week| 3 | %li.week 4 | =link_to week_path(week) do 5 | .week-summary= render ('weeks/summary'), week: week, weeks: true 6 | -------------------------------------------------------------------------------- /app/views/weeks/show.html.haml: -------------------------------------------------------------------------------- 1 | .week-summary 2 | = render 'weeks/summary', week: @week 3 | - if @tasks.present? 4 | = render 'tasks/tasks' 5 | - else 6 | %p.error-message There's no tasks yet. 7 | -------------------------------------------------------------------------------- /app/views/welcome/index.html.haml: -------------------------------------------------------------------------------- 1 | %h1 2 | = image_tag 'ktra.svg', alt: 'K-tra! The Lightweight Task Tracker.', class: 'ktra-image' 3 | .logo K-tra! 4 | .catch The Lightweight Task Tracker. 5 | .sign-in-wrapper 6 | = link_to '/users/auth/twitter', class: 'sign-in' do 7 | %i.fa.fa-twitter 8 | %span Sign in 9 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 7 | 8 | APP_PATH = File.expand_path('../../config/application', __FILE__) 9 | require File.expand_path('../../config/boot', __FILE__) 10 | require 'rails/commands' 11 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require 'bundler/setup' 7 | load Gem.bin_path('rake', 'rake') 8 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require 'bundler/setup' 7 | load Gem.bin_path('rspec-core', 'rspec') 8 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast 4 | # It gets overwritten when you run the `spring binstub` command 5 | 6 | unless defined?(Spring) 7 | require "rubygems" 8 | require "bundler" 9 | 10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) 11 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) 12 | ENV["GEM_HOME"] = nil 13 | Gem.paths = ENV 14 | 15 | gem "spring", match[1] 16 | require "spring/binstub" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | ruby: 3 | version: 2.2.0 4 | timezone: Asia/Tokyo 5 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Ktra::Application 5 | -------------------------------------------------------------------------------- /config/application.example.yml: -------------------------------------------------------------------------------- 1 | TWITTER_KEY: 'hogehoge' 2 | TWITTER_SECRET: 'fugofugo' 3 | production: 4 | BUGSNAG_API_KEY: '' 5 | SECRET_TOKEN: 'aaa' 6 | SESSION_KEY: '_ktra_session' 7 | staging: 8 | RAILS_ENV: 'staging' 9 | RACK_ENV: 'staging' 10 | SECRET_TOKEN: 'bbb' 11 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(:default, Rails.env) 8 | 9 | module Ktra 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | 15 | # Custom directories with classes and modules you want to be autoloadable. 16 | # config.autoload_paths += %W(#{config.root}/extras) 17 | 18 | # Only load the plugins named here, in the order given (default is alphabetical). 19 | # :all can be used as a placeholder for all plugins not explicitly named. 20 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 21 | 22 | # Activate observers that should always be running. 23 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 24 | 25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 27 | # config.time_zone = 'Central Time (US & Canada)' 28 | 29 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 30 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 31 | # config.i18n.default_locale = :de 32 | config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] 33 | I18n.enforce_available_locales = true 34 | config.i18n.default_locale = :ja 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable escaping HTML in JSON. 43 | config.active_support.escape_html_entities_in_json = true 44 | 45 | # Use SQL instead of Active Record's schema dumper when creating the database. 46 | # This is necessary if your schema can't be completely dumped by the schema dumper, 47 | # like if you have constraints or database-specific column types 48 | # config.active_record.schema_format = :sql 49 | 50 | config.sass.line_comments = false 51 | config.sass.cache = false 52 | config.assets.initialize_on_precompile = false 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /config/compass.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | project_type = :rails 3 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | development: &development 2 | adapter: postgresql 3 | database: ktra_development 4 | encoding: utf8 5 | host: localhost 6 | pool: 5 7 | timeout: 5000 8 | 9 | test: 10 | <<: *development 11 | database: ktra_test 12 | 13 | staging: 14 | <<: *development 15 | url: <%= ENV["DATABASE_URL"] %> 16 | 17 | production: 18 | <<: *development 19 | url: <%= ENV["DATABASE_URL"] %> 20 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Ktra::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Ktra::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | config.eager_load = false 10 | 11 | # Show full error reports and disable caching 12 | config.consider_all_requests_local = true 13 | config.action_controller.perform_caching = false 14 | 15 | # Don't care if the mailer can't send 16 | config.action_mailer.raise_delivery_errors = false 17 | 18 | # Print deprecation notices to the Rails logger 19 | config.active_support.deprecation = :log 20 | 21 | # Only use best-standards-support built into browsers 22 | config.action_dispatch.best_standards_support = :builtin 23 | 24 | # Do not compress assets 25 | config.assets.compress = false 26 | 27 | # Expands the lines which load the assets 28 | config.assets.debug = true 29 | end 30 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Ktra::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = true 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = true 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | config.assets.precompile += %w( welcome.js ) 51 | 52 | # Disable delivery errors, bad email addresses will be ignored 53 | # config.action_mailer.raise_delivery_errors = false 54 | 55 | # Enable threaded mode 56 | # config.threadsafe! 57 | 58 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 59 | # the I18n.default_locale when a translation can not be found) 60 | config.i18n.fallbacks = true 61 | 62 | # Send deprecation notices to registered listeners 63 | config.active_support.deprecation = :notify 64 | 65 | config.eager_load = false 66 | 67 | end 68 | -------------------------------------------------------------------------------- /config/environments/staging.rb: -------------------------------------------------------------------------------- 1 | Ktra::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = true 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = true 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | # Log the query plan for queries taking more than this (works 65 | # with SQLite, MySQL, and PostgreSQL) 66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 67 | 68 | config.eager_load = false 69 | 70 | end 71 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Ktra::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_assets = true 17 | config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | 37 | ActionMailer::Base.delivery_method = :test 38 | ActionMailer::Base.perform_deliveries = true 39 | ActionMailer::Base.deliveries = [] 40 | end 41 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/bugsnag.rb: -------------------------------------------------------------------------------- 1 | if Rails.env.production? && ENV['BUGSNAG_API_KEY'].present? 2 | Bugsnag.configure do |config| 3 | config.api_key = ENV['BUGSNAG_API_KEY'] 4 | config.use_ssl = true 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. 2 | # Many of these configuration options can be set straight in your model. 3 | Devise.setup do |config| 4 | # ==> Mailer Configuration 5 | # Configure the e-mail address which will be shown in Devise::Mailer, 6 | # note that it will be overwritten if you use your own mailer class with default "from" parameter. 7 | config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" 8 | 9 | # Configure the class responsible to send e-mails. 10 | # config.mailer = "Devise::Mailer" 11 | 12 | # ==> ORM configuration 13 | # Load and configure the ORM. Supports :active_record (default) and 14 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 15 | # available as additional gems. 16 | require 'devise/orm/active_record' 17 | 18 | # ==> Configuration for any authentication mechanism 19 | # Configure which keys are used when authenticating a user. The default is 20 | # just :email. You can configure it to use [:username, :subdomain], so for 21 | # authenticating a user, both parameters are required. Remember that those 22 | # parameters are used only when authenticating and not when retrieving from 23 | # session. If you need permissions, you should implement that in a before filter. 24 | # You can also supply a hash where the value is a boolean determining whether 25 | # or not authentication should be aborted when the value is not present. 26 | # config.authentication_keys = [ :email ] 27 | 28 | # Configure parameters from the request object used for authentication. Each entry 29 | # given should be a request method and it will automatically be passed to the 30 | # find_for_authentication method and considered in your model lookup. For instance, 31 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 32 | # The same considerations mentioned for authentication_keys also apply to request_keys. 33 | # config.request_keys = [] 34 | 35 | # Configure which authentication keys should be case-insensitive. 36 | # These keys will be downcased upon creating or modifying a user and when used 37 | # to authenticate or find a user. Default is :email. 38 | config.case_insensitive_keys = [ :email ] 39 | 40 | # Configure which authentication keys should have whitespace stripped. 41 | # These keys will have whitespace before and after removed upon creating or 42 | # modifying a user and when used to authenticate or find a user. Default is :email. 43 | config.strip_whitespace_keys = [ :email ] 44 | 45 | # Tell if authentication through request.params is enabled. True by default. 46 | # config.params_authenticatable = true 47 | 48 | # Tell if authentication through HTTP Basic Auth is enabled. False by default. 49 | # config.http_authenticatable = false 50 | 51 | # If http headers should be returned for AJAX requests. True by default. 52 | # config.http_authenticatable_on_xhr = true 53 | 54 | # The realm used in Http Basic Authentication. "Application" by default. 55 | # config.http_authentication_realm = "Application" 56 | 57 | # It will change confirmation, password recovery and other workflows 58 | # to behave the same regardless if the e-mail provided was right or wrong. 59 | # Does not affect registerable. 60 | # config.paranoid = true 61 | 62 | # ==> Configuration for :database_authenticatable 63 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If 64 | # using other encryptors, it sets how many times you want the password re-encrypted. 65 | # 66 | # Limiting the stretches to just one in testing will increase the performance of 67 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 68 | # a value less than 10 in other environments. 69 | config.stretches = Rails.env.test? ? 1 : 10 70 | 71 | # Setup a pepper to generate the encrypted password. 72 | # config.pepper = "717017c2117472e31483d56ea165c69d70c6eb44121393c3db3febfc7b7c65834b75477875773e896a0f39773cec7c9a5cd2a3fd0d236c2f0b600b0f167c5728" 73 | 74 | # ==> Configuration for :confirmable 75 | # A period that the user is allowed to access the website even without 76 | # confirming his account. For instance, if set to 2.days, the user will be 77 | # able to access the website for two days without confirming his account, 78 | # access will be blocked just in the third day. Default is 0.days, meaning 79 | # the user cannot access the website without confirming his account. 80 | # config.confirm_within = 2.days 81 | 82 | # Defines which key will be used when confirming an account 83 | # config.confirmation_keys = [ :email ] 84 | 85 | # ==> Configuration for :rememberable 86 | # The time the user will be remembered without asking for credentials again. 87 | # config.remember_for = 2.weeks 88 | 89 | # If true, a valid remember token can be re-used between multiple browsers. 90 | # config.remember_across_browsers = true 91 | 92 | # If true, extends the user's remember period when remembered via cookie. 93 | # config.extend_remember_period = false 94 | 95 | # Options to be passed to the created cookie. For instance, you can set 96 | # :secure => true in order to force SSL only cookies. 97 | # config.cookie_options = {} 98 | 99 | # ==> Configuration for :validatable 100 | # Range for password length. Default is 6..128. 101 | # config.password_length = 6..128 102 | 103 | # Email regex used to validate email formats. It simply asserts that 104 | # an one (and only one) @ exists in the given string. This is mainly 105 | # to give user feedback and not to assert the e-mail validity. 106 | # config.email_regexp = /\A[^@]+@[^@]+\z/ 107 | 108 | # ==> Configuration for :timeoutable 109 | # The time you want to timeout the user session without activity. After this 110 | # time the user will be asked for credentials again. Default is 30 minutes. 111 | # config.timeout_in = 30.minutes 112 | 113 | # ==> Configuration for :lockable 114 | # Defines which strategy will be used to lock an account. 115 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 116 | # :none = No lock strategy. You should handle locking by yourself. 117 | # config.lock_strategy = :failed_attempts 118 | 119 | # Defines which key will be used when locking and unlocking an account 120 | # config.unlock_keys = [ :email ] 121 | 122 | # Defines which strategy will be used to unlock an account. 123 | # :email = Sends an unlock link to the user email 124 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 125 | # :both = Enables both strategies 126 | # :none = No unlock strategy. You should handle unlocking by yourself. 127 | # config.unlock_strategy = :both 128 | 129 | # Number of authentication tries before locking an account if lock_strategy 130 | # is failed attempts. 131 | # config.maximum_attempts = 20 132 | 133 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 134 | # config.unlock_in = 1.hour 135 | 136 | # ==> Configuration for :recoverable 137 | # 138 | # Defines which key will be used when recovering the password for an account 139 | # config.reset_password_keys = [ :email ] 140 | 141 | # Time interval you can reset your password with a reset password key. 142 | # Don't put a too small interval or your users won't have the time to 143 | # change their passwords. 144 | config.reset_password_within = 2.hours 145 | 146 | # ==> Configuration for :encryptable 147 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use 148 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, 149 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) 150 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy 151 | # REST_AUTH_SITE_KEY to pepper) 152 | # config.encryptor = :sha512 153 | 154 | # ==> Configuration for :token_authenticatable 155 | # Defines name of the authentication token params key 156 | # config.token_authentication_key = :auth_token 157 | 158 | # If true, authentication through token does not store user in session and needs 159 | # to be supplied on each request. Useful if you are using the token as API token. 160 | # config.stateless_token = false 161 | 162 | # ==> Scopes configuration 163 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 164 | # "users/sessions/new". It's turned off by default because it's slower if you 165 | # are using only default views. 166 | # config.scoped_views = false 167 | 168 | # Configure the default scope given to Warden. By default it's the first 169 | # devise role declared in your routes (usually :user). 170 | # config.default_scope = :user 171 | 172 | # Configure sign_out behavior. 173 | # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope). 174 | # The default is true, which means any logout action will sign out all active scopes. 175 | # config.sign_out_all_scopes = true 176 | 177 | # ==> Navigation configuration 178 | # Lists the formats that should be treated as navigational. Formats like 179 | # :html, should redirect to the sign in page when the user does not have 180 | # access, but formats like :xml or :json, should return 401. 181 | # 182 | # If you have any extra navigational formats, like :iphone or :mobile, you 183 | # should add them to the navigational formats lists. 184 | # 185 | # The :"*/*" and "*/*" formats below is required to match Internet 186 | # Explorer requests. 187 | # config.navigational_formats = [:"*/*", "*/*", :html] 188 | 189 | # The default HTTP method used to sign out a resource. Default is :delete. 190 | config.sign_out_via = :delete 191 | 192 | # ==> OmniAuth 193 | # Add a new OmniAuth provider. Check the wiki for more information on setting 194 | # up on your models and hooks. 195 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' 196 | config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'], { 197 | secure_image_url: 'true', 198 | image_size: 'bigger', # 大きい画像を使っちゃおうね 199 | } 200 | 201 | # ==> Warden configuration 202 | # If you want to use other strategies, that are not supported by Devise, or 203 | # change the failure app, you can configure them inside the config.warden block. 204 | # 205 | # config.warden do |manager| 206 | # manager.intercept_401 = false 207 | # manager.default_strategies(:scope => :user).unshift :some_external_strategy 208 | # end 209 | 210 | config.secret_key = '625bef6226fac9196d9c0a0853c24c1bb4e183e3c17affd83bb8a801eb23e81066e2b2143fcd6807c9d211aee998c6a44a24321dc1b55ce8214ed4318fa8c982' 211 | end 212 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Ktra::Application.config.session_store :cookie_store, key: ENV['SESSION_KEY'] || "_ktra_session_#{Rails.env}", expire_after: 1.months 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Ktra::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/locales/devise/en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | errors: 5 | messages: 6 | expired: "has expired, please request a new one" 7 | not_found: "not found" 8 | already_confirmed: "was already confirmed, please try signing in" 9 | not_locked: "was not locked" 10 | not_saved: 11 | one: "1 error prohibited this %{resource} from being saved:" 12 | other: "%{count} errors prohibited this %{resource} from being saved:" 13 | 14 | devise: 15 | failure: 16 | already_authenticated: 'You are already signed in.' 17 | unauthenticated: 'You need to sign in or sign up before continuing.' 18 | unconfirmed: 'You have to confirm your account before continuing.' 19 | locked: 'Your account is locked.' 20 | invalid: 'Invalid email or password.' 21 | invalid_token: 'Invalid authentication token.' 22 | timeout: 'Your session expired, please sign in again to continue.' 23 | inactive: 'Your account was not activated yet.' 24 | sessions: 25 | signed_in: 'Signed in successfully.' 26 | signed_out: 'Signed out successfully.' 27 | passwords: 28 | send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' 29 | updated: 'Your password was changed successfully. You are now signed in.' 30 | updated_not_active: 'Your password was changed successfully.' 31 | send_paranoid_instructions: "If your e-mail exists on our database, you will receive a password recovery link on your e-mail" 32 | confirmations: 33 | send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' 34 | send_paranoid_instructions: 'If your e-mail exists on our database, you will receive an email with instructions about how to confirm your account in a few minutes.' 35 | confirmed: 'Your account was successfully confirmed. You are now signed in.' 36 | registrations: 37 | signed_up: 'Welcome! You have signed up successfully.' 38 | inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.' 39 | updated: 'You updated your account successfully.' 40 | destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' 41 | reasons: 42 | inactive: 'inactive' 43 | unconfirmed: 'unconfirmed' 44 | locked: 'locked' 45 | unlocks: 46 | send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' 47 | unlocked: 'Your account was successfully unlocked. You are now signed in.' 48 | send_paranoid_instructions: 'If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.' 49 | omniauth_callbacks: 50 | success: 'Successfully authorized from %{kind} account.' 51 | failure: 'Could not authorize you from %{kind} because "%{reason}".' 52 | mailer: 53 | confirmation_instructions: 54 | subject: 'Confirmation instructions' 55 | reset_password_instructions: 56 | subject: 'Reset password instructions' 57 | unlock_instructions: 58 | subject: 'Unlock Instructions' 59 | -------------------------------------------------------------------------------- /config/locales/devise/ja.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | ja: 4 | errors: 5 | messages: 6 | expired: "有効期限切れです。新規登録してください" 7 | not_found: "は見つかりませんでした" 8 | already_confirmed: "は既に登録済みです。ログインしてください" 9 | not_locked: "ロックされていません" 10 | not_saved: 11 | one: "エラーがあります" 12 | other: "エラーがあります" 13 | devise: 14 | failure: 15 | already_authenticated: 'ログイン済みです' 16 | inactive: 'アカウントがまだ有効になっていません' 17 | invalid: 'メールアドレスまたはパスワードが違います' 18 | invalid_token: '認証キーが不正です' 19 | locked: 'アカウントはロックされています' 20 | not_found_in_database: "メールアドレスまたはパスワードが違います" 21 | timeout: '一定時間が経過したため、再度ログインが必要です' 22 | unauthenticated: 'ログインまたは登録が必要です' 23 | unconfirmed: '本登録を行ってください' 24 | sessions: 25 | signed_in: 'ログインしました' 26 | signed_out: 'ログアウトしました' 27 | passwords: 28 | send_instructions: 'パスワードのリセット方法を記載したメールを送信しました' 29 | updated: 'パスワードを変更しました。ログイン済みです' 30 | updated_not_active: 'パスワードを変更しました' 31 | send_paranoid_instructions: "ご登録のメールアドレスが保存されている場合、パスワード復旧用のリンク先をメールでご連絡します" 32 | confirmations: 33 | send_instructions: 'アカウントの確認方法を数分以内にメールでご連絡します' 34 | send_paranoid_instructions: 'ご登録のメールアドレスが保存されている場合、アカウントの確認方法をメールでご連絡します' 35 | confirmed: 'アカウントが確認されました。ログインしています' 36 | registrations: 37 | destroyed: 'ご利用ありがとうございました。アカウントが削除されました。またのご利用をお待ちしています' 38 | signed_up: 'ようこそ! アカウントが登録されました' 39 | signed_up_but_inactive: 'アカウントがアクティブではないようです。' 40 | signed_up_but_locked: 'アカウントがロックされてます' 41 | signed_up_but_unconfirmed: 'アカウントのメールアドレスが未確認です' 42 | update_needs_confirmation: "アカウント情報の更新をしましたが、新しいメールアドレスの確認がされていません。確認メールをご確認下さい。" 43 | inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.' 44 | updated: 'You updated your account successfully.' 45 | reasons: 46 | inactive: 'inactive' 47 | unconfirmed: 'unconfirmed' 48 | locked: 'locked' 49 | unlocks: 50 | send_instructions: 'アカウントのロックを解除する方法を数分以内にメールでご連絡します' 51 | unlocked: 'アカウントのロックが解除されました。ログインしています。' 52 | send_paranoid_instructions: 'アカウントが存在する場合、ロックを解除する方法をメールでご連絡します' 53 | omniauth_callbacks: 54 | success: '%{kind}アカウントでログインしました。' 55 | failure: '%{kind} から承認されませんでした。理由:"%{reason}".' 56 | mailer: 57 | confirmation_instructions: 58 | subject: 'アカウントの登録方法' 59 | reset_password_instructions: 60 | subject: 'パスワードの再設定' 61 | unlock_instructions: 62 | subject: 'アカウントのロック解除' 63 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /config/locales/ja.yml: -------------------------------------------------------------------------------- 1 | ja: 2 | hello: "Hello world" 3 | 4 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Ktra::Application.routes.draw do 2 | devise_for :users, controllers: { omniauth_callbacks: 'sessions' }, skip: [:sessions] 3 | devise_scope :user do 4 | delete '/sessions' => 'devise/sessions#destroy', as: :user_session 5 | end 6 | resources :tasks do 7 | member do 8 | post 'done' 9 | end 10 | resource :status, only: [:update] 11 | end 12 | resources :weeks do 13 | resources :tasks 14 | end 15 | authenticated :user do 16 | root 'tasks#index', as: :authenticated_user_root 17 | end 18 | root :to => 'welcome#index' 19 | get '/auth/failure' => 'sessions#failure' 20 | resource :account, only: [:show] 21 | 22 | # The priority is based upon order of creation: 23 | # first created -> highest priority. 24 | 25 | # Sample of regular route: 26 | # match 'products/:id' => 'catalog#view' 27 | # Keep in mind you can assign values other than :controller and :action 28 | 29 | # Sample of named route: 30 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 31 | # This route can be invoked with purchase_url(:id => product.id) 32 | 33 | # Sample resource route (maps HTTP verbs to controller actions automatically): 34 | # resources :products 35 | 36 | # Sample resource route with options: 37 | # resources :products do 38 | # member do 39 | # get 'short' 40 | # post 'toggle' 41 | # end 42 | # 43 | # collection do 44 | # get 'sold' 45 | # end 46 | # end 47 | 48 | # Sample resource route with sub-resources: 49 | # resources :products do 50 | # resources :comments, :sales 51 | # resource :seller 52 | # end 53 | 54 | # Sample resource route with more complex sub-resources 55 | # resources :products do 56 | # resources :comments 57 | # resources :sales do 58 | # get 'recent', :on => :collection 59 | # end 60 | # end 61 | 62 | # Sample resource route within a namespace: 63 | # namespace :admin do 64 | # # Directs /admin/products/* to Admin::ProductsController 65 | # # (app/controllers/admin/products_controller.rb) 66 | # resources :products 67 | # end 68 | 69 | # You can have the root of your site routed with "root" 70 | # just remember to delete public/index.html. 71 | # root :to => 'welcome#index' 72 | 73 | # See how all your routes lay out with "rake routes" 74 | 75 | # This is a legacy wild controller route that's not recommended for RESTful applications. 76 | # Note: This route will make all actions in every controller accessible via GET requests. 77 | # match ':controller(/:action(/:id))(.:format)' 78 | end 79 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | development: 2 | secret_key_base: f1266f11f1e7ae4f53d75d2e0b70e7a9114258db1bee71dbfc505c2e57d6ee009ca1860f4e9d9e9b36475c02f66f67f31aece46b02937d53c110c4992b0fbbb3 3 | 4 | test: 5 | secret_key_base: f1266f11f1e7ae4f53d75d2e0b70e7a9114258db1bee71dbfc505c2e57d6ee009ca1860f4e9d9e9b36475c02f66f67f31aece46b02937d53c110c4992b0fbbb3 6 | 7 | production: 8 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 9 | -------------------------------------------------------------------------------- /db/migrate/20130425112957_create_tasks.rb: -------------------------------------------------------------------------------- 1 | class CreateTasks < ActiveRecord::Migration 2 | def change 3 | create_table :tasks do |t| 4 | t.string :title 5 | t.integer :point 6 | t.string :status 7 | t.text :memo 8 | t.datetime :started_at 9 | t.datetime :finished_at 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130619112425_create_iterations.rb: -------------------------------------------------------------------------------- 1 | class CreateIterations < ActiveRecord::Migration 2 | def change 3 | create_table :iterations do |t| 4 | t.date :start_date 5 | t.date :end_date 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130619113001_add_iteration_id_to_tasks.rb: -------------------------------------------------------------------------------- 1 | class AddIterationIdToTasks < ActiveRecord::Migration 2 | def change 3 | add_column :tasks, :iteration_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130815115856_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table :users do |t| 4 | t.string :uid, null: false 5 | t.string :name 6 | t.string :nickname 7 | t.string :image 8 | t.string :token 9 | t.string :secret 10 | 11 | t.timestamps 12 | end 13 | add_index :users, :uid, unique: true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20140306103013_add_user_id_to_tasks.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToTasks < ActiveRecord::Migration 2 | def change 3 | add_column :tasks, :user_id, :integer 4 | add_index :tasks, :user_id 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20140401074621_change_iterations_to_weeks.rb: -------------------------------------------------------------------------------- 1 | class ChangeIterationsToWeeks < ActiveRecord::Migration 2 | def change 3 | rename_column :tasks, :iteration_id, :week_id 4 | rename_table :iterations, :weeks 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20140401074621) do 15 | 16 | # These are extensions that must be enabled in order to support this database 17 | enable_extension "plpgsql" 18 | 19 | create_table "tasks", force: true do |t| 20 | t.string "title" 21 | t.integer "point" 22 | t.string "status" 23 | t.text "memo" 24 | t.datetime "started_at" 25 | t.datetime "finished_at" 26 | t.datetime "created_at" 27 | t.datetime "updated_at" 28 | t.integer "week_id" 29 | t.integer "user_id" 30 | end 31 | 32 | add_index "tasks", ["user_id"], name: "index_tasks_on_user_id", using: :btree 33 | 34 | create_table "users", force: true do |t| 35 | t.string "uid", null: false 36 | t.string "name" 37 | t.string "nickname" 38 | t.string "image" 39 | t.string "token" 40 | t.string "secret" 41 | t.datetime "created_at" 42 | t.datetime "updated_at" 43 | end 44 | 45 | add_index "users", ["uid"], name: "index_users_on_uid", unique: true, using: :btree 46 | 47 | create_table "weeks", force: true do |t| 48 | t.date "start_date" 49 | t.date "end_date" 50 | t.datetime "created_at" 51 | t.datetime "updated_at" 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /doc/apple-touch-icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/apple-touch-icon.psd -------------------------------------------------------------------------------- /doc/favicon/favicon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-128.png -------------------------------------------------------------------------------- /doc/favicon/favicon-128.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-128.psd -------------------------------------------------------------------------------- /doc/favicon/favicon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-16.png -------------------------------------------------------------------------------- /doc/favicon/favicon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-32.png -------------------------------------------------------------------------------- /doc/favicon/favicon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-48.png -------------------------------------------------------------------------------- /doc/favicon/favicon-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon-96.png -------------------------------------------------------------------------------- /doc/favicon/favicon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/favicon/favicon.psd -------------------------------------------------------------------------------- /doc/ktra-design.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/ktra-design.ai -------------------------------------------------------------------------------- /doc/ktra-goods-base.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/ktra-goods-base.ai -------------------------------------------------------------------------------- /doc/ktra-tshirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/doc/ktra-tshirt.png -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/log/.gitkeep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /spec/controllers/accounts_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe AccountsController do 4 | let(:user) { create(:user) } 5 | 6 | before do 7 | sign_in user 8 | end 9 | 10 | describe 'GET #show' do 11 | it 'json is works' do 12 | get :show, format: :json 13 | expect(response).to be_success 14 | end 15 | end 16 | 17 | describe 'hoge' do 18 | it { expect(user).to be_valid } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/controllers/statuses_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe StatusesController do 4 | let(:user) { create(:user) } 5 | let(:task) { create :task, user_id: user.id } 6 | 7 | before do 8 | sign_in user 9 | end 10 | 11 | context 'with {format: :js}' do 12 | describe 'PUT #update' do 13 | let(:task_param) do 14 | { 15 | status: 'start', 16 | week_id: 1 17 | } 18 | end 19 | 20 | it 'js is works' do 21 | put :update, task_id: task.id, task: task_param, format: :js 22 | expect(response).to be_success 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/controllers/tasks_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe TasksController do 4 | let(:user) { create(:user) } 5 | 6 | before do 7 | sign_in user 8 | end 9 | 10 | let(:task) { create :task, user_id: user.id } 11 | let(:task_params) { attributes_for :task, user_id: user.id } 12 | 13 | context 'with {format: :html}' do 14 | describe 'GET #edit' do 15 | it 'redirect_to root_url' do 16 | get :edit, id: task.id 17 | expect(response).to redirect_to root_url 18 | end 19 | end 20 | end 21 | 22 | context 'with {format: :json}' do 23 | describe 'GET #index' do 24 | it 'json is works' do 25 | get :index, {format: :json} 26 | expect(response).to be_success 27 | end 28 | end 29 | 30 | describe 'POST #create' do 31 | it 'json is works' do 32 | post :create, task: task_params, format: :json 33 | expect(response).to be_success 34 | end 35 | end 36 | 37 | describe 'GET #show' do 38 | it 'json is works' do 39 | get :show, id: task.id, format: :json 40 | expect(response).to be_success 41 | end 42 | end 43 | 44 | describe 'PUT #update' do 45 | it 'json is works' do 46 | put :update, id: task.id, task: task_params, format: :json 47 | expect(response).to be_success 48 | end 49 | end 50 | 51 | describe 'DELETE #destoy' do 52 | it 'json is works' do 53 | delete :destroy, id: task.id, format: :json 54 | expect(response).to be_success 55 | end 56 | end 57 | end 58 | 59 | context 'with {format: :js}' do 60 | describe 'POST #create' do 61 | it 'js is works' do 62 | post :create, task: task_params, format: :js 63 | expect(response).to be_success 64 | end 65 | end 66 | 67 | describe 'GET #edit' do 68 | it 'js is works' do 69 | xhr :get, :edit, id: task.id, format: :js 70 | expect(response).to be_success 71 | end 72 | end 73 | 74 | describe 'PUT #update' do 75 | it 'js is works' do 76 | put :update, id: task.id, task: task_params, format: :js 77 | expect(response).to be_success 78 | end 79 | end 80 | 81 | describe 'DELETE #destoy' do 82 | it 'js is works' do 83 | delete :destroy, id: task.id, format: :js 84 | expect(response).to be_success 85 | end 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /spec/controllers/weeks_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe WeeksController do 4 | let(:user) { create(:user) } 5 | 6 | before do 7 | sign_in user 8 | end 9 | 10 | context 'with {format: :json}' do 11 | describe 'GET #index' do 12 | it 'json is works' do 13 | get :index, {format: :json} 14 | expect(response).to be_success 15 | end 16 | end 17 | 18 | let(:week) { create :week } 19 | 20 | describe 'GET #show' do 21 | it 'json is works' do 22 | get :show, id: week.id, format: :json 23 | expect(response).to be_success 24 | end 25 | end 26 | end 27 | end 28 | 29 | -------------------------------------------------------------------------------- /spec/factories/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/spec/factories/.gitkeep -------------------------------------------------------------------------------- /spec/factories/tasks.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :task, class: 'Task' do 3 | title { Faker::Name.title } 4 | point { 1 } 5 | user_id { 1 } 6 | memo { Faker::Lorem.paragraphs.join("\n") } 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | sequence :uid do |n| 3 | "#{n.to_s}" 4 | end 5 | factory :user, class: 'User' do 6 | uid 7 | name { Faker::Name.name } 8 | nickname { Faker::Name.name } 9 | image { Faker::Internet.url } 10 | token 'token' 11 | secret 'secret' 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/factories/weeks.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :week, class: 'Week' do 3 | start_date { Date.current } 4 | end_date { Date.current } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/features/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/spec/features/.gitkeep -------------------------------------------------------------------------------- /spec/features/sign_in_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe 'sign_in' do 4 | let(:new_user) { build(:user) } 5 | 6 | describe 'twitter ログイン' do 7 | before do 8 | oauth_sign_in(new_user, :twitter, false) 9 | end 10 | it 'ログインしたユーザー名が表示される' do 11 | within('.header .user .name') do 12 | expect(page).to have_content new_user.nickname 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/features/tasks_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | feature 'Tasks List Spec' do 4 | let(:user) { create :user } 5 | 6 | background do 7 | oauth_sign_in(user, :twitter, false) 8 | end 9 | 10 | scenario 'Display Task Form after Sign in' do 11 | expect(page).to have_text('There\'s no tasks yet') 12 | end 13 | 14 | context 'with tasks' do 15 | let!(:task) { create :task } 16 | 17 | context "with \'unstarted\' task ( default status )" do 18 | scenario 'should have \'START\' button' do 19 | visit '/' 20 | expect(page).to have_text('START') 21 | end 22 | end 23 | 24 | context "with \'doing\' task" do 25 | background do 26 | task.status = 'doing' 27 | task.save 28 | end 29 | 30 | scenario 'should have \'DONE\' button' do 31 | visit '/' 32 | expect(page).to have_text('DONE') 33 | end 34 | end 35 | 36 | context "with \'done\' task" do 37 | background do 38 | task.title = 'DONED TASK' 39 | task.status = 'done' 40 | task.save 41 | end 42 | 43 | scenario 'DONE task should not displayed at root' do 44 | visit '/' 45 | expect(page).to_not have_text('DONED TASK') 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/spec/models/.gitkeep -------------------------------------------------------------------------------- /spec/models/task_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Task do 4 | let(:task) { create(:task) } 5 | describe 'タスクが生成出来る' do 6 | subject { task } 7 | it { expect(subject).to be_instance_of Task } 8 | end 9 | 10 | describe '.owned_by' do 11 | subject { Task.owned_by(current_user) } 12 | let(:current_user) { create(:user) } 13 | 14 | context 'タスクが存在しない場合' do 15 | let(:tasks) { [] } 16 | it '空の配列を取得すること' do 17 | expect(subject).to eq tasks 18 | end 19 | end 20 | 21 | context 'タスクが存在する場合' do 22 | let(:task1) { create(:task, point: 2, user_id: current_user.id) } 23 | let(:task2) { create(:task, point: 5, user_id: current_user.id) } 24 | 25 | context '引数にユーザを指定した場合' do 26 | it 'そのユーザのタスクが取得できること' do 27 | expect(subject).to include(task1, task2) 28 | end 29 | 30 | context '他人のタスクが存在する場合' do 31 | let(:other) { create(:user) } 32 | let(:other_task1) { create(:task, point: 3, user_id: other.id) } 33 | let(:other_task2) { create(:task, point: 8, user_id: other.id) } 34 | 35 | it '他人のタスクが混ざらないこと' do 36 | expect(subject).to_not include(other_task1, other_task2) 37 | end 38 | end 39 | end 40 | 41 | context '引数にユーザを指定しない場合' do 42 | let(:current_user) { nil } 43 | let(:tasks) { [] } 44 | let!(:other) { create(:user) } 45 | let!(:others_tasks) { 46 | [ 47 | create(:task, point: 3, user_id: other.id), 48 | create(:task, point: 8, user_id: other.id) 49 | ] 50 | } 51 | 52 | it '空の配列を取得すること' do 53 | expect(subject).to eq tasks 54 | end 55 | end 56 | end 57 | end 58 | 59 | describe '#set_default_status' do 60 | let(:task) { create :task, status: nil } 61 | it 'should set default status before create' do 62 | expect(task.status).to eq('unstarted') 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | let(:user) { create(:user) } 5 | let(:valid_auth_hash) { 6 | { 7 | 'provider' => 'twitter', 8 | 'uid' => '123456', 9 | 'info' => { 10 | 'nickname' => 'ken_c_lo', 11 | 'name' => 'いぬです', 12 | 'image' => 'https://a0.twimg.com/profile_images/2900491556/9d2bf873770958647f18b8e61af31f1a_bigger.png' 13 | }, 14 | 'credentials' => { 15 | 'token' => '123445678-AbeafjabutWjfav932m38e3TTabbbbbk', 16 | 'secret' => 'UzOc15tGx8AMYLOX5dcZ2UQTEwe6LiVysdoyhiKlaw' 17 | } 18 | } 19 | } 20 | 21 | describe 'ユーザーが生成出来る' do 22 | subject { user } 23 | it { expect(subject).to be_instance_of User } 24 | end 25 | 26 | describe '.authentication' do 27 | let(:auth_hash) { nil } 28 | let(:current_user) { nil } 29 | subject { User.authentication(auth_hash, current_user) } 30 | 31 | context 'auth_hashがない' do 32 | it { expect(subject).to be_nil } 33 | end 34 | 35 | context 'auth_hashがある' do 36 | let(:auth_hash) { valid_auth_hash } 37 | context 'userが居る' do 38 | before do 39 | user.uid = auth_hash['uid'] 40 | user.save 41 | user.reload 42 | end 43 | it { expect(subject).to eq user } 44 | it { expect(subject).to be_instance_of User } 45 | end 46 | 47 | context 'userがいない' do 48 | let(:new_user) { create(:user) } 49 | before do 50 | allow(User).to receive_message_chain(:where, :first_or_initialize).and_return(new_user) 51 | end 52 | it { expect(subject).to eq new_user } 53 | it { expect(subject).to be_instance_of User } 54 | end 55 | it { expect(subject.image).to match '_bigger' } 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/models/week_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Week do 4 | let(:week) { create(:week) } 5 | describe 'イテレーションが生成出来る' do 6 | subject { week } 7 | it { expect(subject).to be_instance_of Week } 8 | end 9 | 10 | describe '.since_first_task_by' do 11 | let!(:past_weeks) { [Week.current(1.week.ago), Week.current(2.week.ago), Week.current(3.week.ago)]} 12 | let!(:current_week) { Week.current } 13 | let(:current_user) { create(:user) } 14 | subject { Week.since_first_task_by(current_user) } 15 | 16 | context 'タスクが存在しない場合' do 17 | it { expect(subject).not_to be_include current_week } 18 | it { expect(subject).not_to be_include past_weeks[0] } 19 | it { expect(subject).not_to be_include past_weeks[1] } 20 | it { expect(subject).not_to be_include past_weeks[2] } 21 | end 22 | 23 | context '2週間前のタスクが存在する場合' do 24 | let!(:task) { create(:task, user: current_user, created_at: 2.week.ago) } 25 | it { expect(subject).to be_include current_week } 26 | it { expect(subject).to be_include past_weeks[0] } 27 | it { expect(subject).to be_include past_weeks[1] } 28 | it { expect(subject).not_to be_include past_weeks[2] } 29 | end 30 | end 31 | 32 | describe '#total_point' do 33 | let(:current_user) { create(:user) } 34 | subject { week.total_point(current_user) } 35 | context 'タスクが存在する場合' do 36 | let(:tasks) { 37 | [ 38 | create(:task, point: 2, user_id: current_user.id, week_id: week.id), 39 | create(:task, point: 5, user_id: current_user.id, week_id: week.id) 40 | ] 41 | } 42 | let(:total_point) { tasks.sum(&:point) } 43 | 44 | before do 45 | week.tasks = tasks 46 | end 47 | 48 | it '合計値が算出できること' do 49 | expect(subject).to eq total_point 50 | end 51 | 52 | context '他人のタスクが存在する場合' do 53 | let!(:other) { create(:user) } 54 | let!(:others_tasks) { 55 | [ 56 | create(:task, point: 3, user_id: other.id, week_id: week.id), 57 | create(:task, point: 8, user_id: other.id, week_id: week.id) 58 | ] 59 | } 60 | 61 | it '他人のタスクが混ざらないこと' do 62 | expect(subject).to eq total_point 63 | end 64 | end 65 | end 66 | 67 | context 'タスクが存在しない場合' do 68 | let(:total_point) { 0 } 69 | it '合計値が算出できること' do 70 | expect(subject).to eq total_point 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= 'test' 2 | require File.expand_path("../../config/environment", __FILE__) 3 | require 'rspec/rails' 4 | require 'json_expressions/rspec' 5 | 6 | # Load all railties files 7 | Rails.application.railties.to_a { |r| r.eager_load! } 8 | 9 | # Requires supporting ruby files with custom matchers and macros, etc, 10 | # in spec/support/ and its subdirectories. 11 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 12 | 13 | RSpec.configure do |config| 14 | config.raise_errors_for_deprecations! 15 | config.infer_spec_type_from_file_location! 16 | 17 | # ## Mock Framework 18 | # 19 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 20 | # 21 | # config.mock_with :mocha 22 | # config.mock_with :flexmock 23 | # config.mock_with :rr 24 | 25 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 26 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 27 | 28 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 29 | # examples within a transaction, remove the following line or assign false 30 | # instead of true. 31 | config.use_transactional_fixtures = false 32 | 33 | # If true, the base class of anonymous controllers will be inferred 34 | # automatically. This will be the default behavior in future versions of 35 | # rspec-rails. 36 | config.infer_base_class_for_anonymous_controllers = false 37 | 38 | # Run specs in random order to surface order dependencies. If you find an 39 | # order dependency and want to debug it, you can fix the order by providing 40 | # the seed, which is printed after each run. 41 | # --seed 1234 42 | config.order = "random" 43 | 44 | # For capybara 45 | require 'capybara/rspec' 46 | require 'capybara/poltergeist' 47 | Capybara.register_driver :rack_test do |app| 48 | Capybara::RackTest::Driver.new(app, headers: {'HTTP_ACCEPT_LANGUAGE' => 'ja-JP'}) 49 | end 50 | Capybara.register_driver :poltergeist do |app| 51 | Capybara::Poltergeist::Driver.new(app, timeout: 360, headers: {'HTTP_ACCEPT_LANGUAGE' => 'ja-JP'}) 52 | end 53 | Capybara.javascript_driver = :poltergeist 54 | 55 | # For database cleaner 56 | config.before(:suite) do 57 | DatabaseCleaner.strategy = :truncation 58 | end 59 | 60 | config.before(:each) do |example| 61 | if example.metadata[:js] 62 | page.driver.resize(1024, 2048) 63 | end 64 | I18n.locale = (ENV['CI'] == 'ON') ? :en : :ja 65 | DatabaseCleaner.strategy = :truncation 66 | end 67 | 68 | config.after(:each) do |example| 69 | DatabaseCleaner.clean 70 | if example.metadata[:js] 71 | load "#{Rails.root}/db/seeds.rb" 72 | end 73 | end 74 | 75 | # macro 76 | config.include FeatureMacros, type: :feature 77 | config.include FactoryGirl::Syntax::Methods 78 | config.include Delorean 79 | 80 | # metadata setting 81 | #config.treat_symbols_as_metadata_keys_with_true_values = true 82 | 83 | config.before(:all) do 84 | FactoryGirl.reload 85 | end 86 | 87 | # faker 88 | Faker::Config.locale = :en 89 | 90 | # master data 91 | #load "#{Rails.root}/db/seeds.rb" 92 | end 93 | -------------------------------------------------------------------------------- /spec/routing/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/spec/routing/.gitkeep -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | RSpec.configure do |config| 20 | # rspec-expectations config goes here. You can use an alternate 21 | # assertion/expectation library such as wrong or the stdlib/minitest 22 | # assertions if you prefer. 23 | config.expect_with :rspec do |expectations| 24 | # This option will default to `true` in RSpec 4. It makes the `description` 25 | # and `failure_message` of custom matchers include text for helper methods 26 | # defined using `chain`, e.g.: 27 | # be_bigger_than(2).and_smaller_than(4).description 28 | # # => "be bigger than 2 and smaller than 4" 29 | # ...rather than: 30 | # # => "be bigger than 2" 31 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 32 | end 33 | 34 | # rspec-mocks config goes here. You can use an alternate test double 35 | # library (such as bogus or mocha) by changing the `mock_with` option here. 36 | config.mock_with :rspec do |mocks| 37 | # Prevents you from mocking or stubbing a method that does not exist on 38 | # a real object. This is generally recommended, and will default to 39 | # `true` in RSpec 4. 40 | mocks.verify_partial_doubles = true 41 | end 42 | 43 | # The settings below are suggested to provide a good initial experience 44 | # with RSpec, but feel free to customize to your heart's content. 45 | =begin 46 | # These two settings work together to allow you to limit a spec run 47 | # to individual examples or groups you care about by tagging them with 48 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 49 | # get run. 50 | config.filter_run :focus 51 | config.run_all_when_everything_filtered = true 52 | 53 | # Limits the available syntax to the non-monkey patched syntax that is 54 | # recommended. For more details, see: 55 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 56 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 57 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 58 | config.disable_monkey_patching! 59 | 60 | # Many RSpec users commonly either run the entire suite or an individual 61 | # file, and it's useful to allow more verbose output when running an 62 | # individual spec file. 63 | if config.files_to_run.one? 64 | # Use the documentation formatter for detailed output, 65 | # unless a formatter has already been configured 66 | # (e.g. via a command-line flag). 67 | config.default_formatter = 'doc' 68 | end 69 | 70 | # Print the 10 slowest examples and example groups at the 71 | # end of the spec run, to help surface which specs are running 72 | # particularly slow. 73 | config.profile_examples = 10 74 | 75 | # Run specs in random order to surface order dependencies. If you find an 76 | # order dependency and want to debug it, you can fix the order by providing 77 | # the seed, which is printed after each run. 78 | # --seed 1234 79 | config.order = :random 80 | 81 | # Seed global randomization in this process using the `--seed` CLI option. 82 | # Setting this allows you to use `--seed` to deterministically reproduce 83 | # test failures related to randomization by passing the same `--seed` value 84 | # as the one that triggered the failure. 85 | Kernel.srand config.seed 86 | =end 87 | end 88 | -------------------------------------------------------------------------------- /spec/support/controller.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.include Devise::TestHelpers, type: :controller 3 | end 4 | -------------------------------------------------------------------------------- /spec/support/feature_macros.rb: -------------------------------------------------------------------------------- 1 | include Warden::Test::Helpers 2 | module FeatureMacros 3 | extend ActiveSupport::Concern 4 | 5 | included do 6 | let(:auth_hash) { 7 | { 8 | 'provider' => 'twitter', 9 | 'uid' => '12345', 10 | 'info' => { 11 | 'nickname' => 'ppworks', 12 | 'name' => 'PP works', 13 | 'image' => 'https://a0.twimg.com/profile_images/2900491556/9d2bf873770958647f18b8e61af31f1a_bigger.png' 14 | }, 15 | 'credentials' => { 16 | 'token' => '123445678-AbeafjabutWjfav932m38e3TTabbbbbk', 17 | 'secret' => 'UzOc15tGx8AMYLOX5dcZ2UQTEwe6LiVysdoyhiKlaw' 18 | } 19 | } 20 | } 21 | after do 22 | Warden.test_reset! 23 | end 24 | end 25 | 26 | def oauth_sign_in user, provider, force_reload = true 27 | back_path = page.current_path 28 | auth = 29 | { 30 | 'uid' => user.uid, 31 | 'info' => { 32 | 'name' => user.name, 33 | 'nickname' => user.nickname, 34 | 'image' => user.image, 35 | 'email' => '', 36 | }, 37 | 'credentials' => { 38 | 'token' => 'token', 39 | 'secret' => 'secret' 40 | }, 41 | 'extra' => { 42 | 'raw_info' => { 43 | 'avatar_url' => user.image 44 | } 45 | } 46 | } 47 | auth[:provider] = provider 48 | OmniAuth.config.test_mode = true 49 | OmniAuth.config.mock_auth[provider.to_sym] = OmniAuth::AuthHash.new(auth) 50 | visit "/users/auth/#{provider.to_s}" 51 | visit back_path if back_path 52 | reload if force_reload 53 | end 54 | 55 | def sign_in(user) 56 | Warden.test_mode! 57 | user.confirm! if user.respond_to?(:confirm!) 58 | scope = user.class.to_s.downcase.to_sym 59 | login_as(user, scope: scope, run_callbacks: false) 60 | end 61 | 62 | def sign_out(user = nil) 63 | if user 64 | scope = user.class.to_s.downcase.to_sym 65 | logout(scope) 66 | else 67 | logout 68 | end 69 | end 70 | 71 | def reload 72 | visit page.current_path if page.current_path 73 | end 74 | 75 | def wait_for_ajax 76 | Timeout.timeout(10) do 77 | loop do 78 | active = page.evaluate_script('jQuery.active') 79 | break if active == 0 80 | end 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/vendor/assets/javascripts/.gitkeep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/vendor/assets/stylesheets/.gitkeep -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taea/ktra/927b4829ac3c40c8db345e393f128621de84cb78/vendor/plugins/.gitkeep -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/rvm 2 | services: 3 | - wercker/postgresql 4 | build: 5 | steps: 6 | - rvm-use: 7 | version: 2.2.0 8 | - bundle-install 9 | - rails-database-yml: 10 | service: postgresql 11 | - script: 12 | name: echo ruby information 13 | code: | 14 | echo "ruby version $(ruby --version) running" 15 | echo "from location $(which ruby)" 16 | echo -p "gem list: $(gem list)" 17 | - script: 18 | name: Set up application.yml 19 | code: cp config/application.example.yml config/application.yml 20 | - script: 21 | name: Create tmp dir 22 | code: bundle exec rake tmp:create 23 | - script: 24 | name: CI env 25 | code: export CI='ON' 26 | - script: 27 | name: Set up db 28 | code: RAILS_ENV=test bundle exec rake db:schema:load 29 | - script: 30 | name: Run RSpec 31 | code: bundle exec rspec 32 | --------------------------------------------------------------------------------