xrono 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +20 -0
  4. data/Gemfile +30 -0
  5. data/Gemfile.lock +336 -0
  6. data/LICENSE +21 -0
  7. data/README.md +64 -0
  8. data/RELEASE_NOTES.md +83 -0
  9. data/Rakefile +15 -0
  10. data/XRONO.md +64 -0
  11. data/app/assets/images/chosen-sprite.png +0 -0
  12. data/app/assets/images/grid.png +0 -0
  13. data/app/assets/images/isotope_logo.png +0 -0
  14. data/app/assets/images/logo.png +0 -0
  15. data/app/assets/images/logo_122x40.png +0 -0
  16. data/app/assets/images/logo_97x40.png +0 -0
  17. data/app/assets/images/main_bg.jpg +0 -0
  18. data/app/assets/images/nav_bg.jpg +0 -0
  19. data/app/assets/images/rails.png +0 -0
  20. data/app/assets/images/top_bg.jpg +0 -0
  21. data/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  22. data/app/assets/images/ui-bg_flat_0_fbf9ee_40x100.png +0 -0
  23. data/app/assets/images/ui-bg_flat_55_fbec88_40x100.png +0 -0
  24. data/app/assets/images/ui-bg_flat_65_ffffff_40x100.png +0 -0
  25. data/app/assets/images/ui-bg_flat_75_cccccc_40x100.png +0 -0
  26. data/app/assets/images/ui-bg_flat_75_dadada_40x100.png +0 -0
  27. data/app/assets/images/ui-bg_flat_75_e6e6e6_40x100.png +0 -0
  28. data/app/assets/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  29. data/app/assets/images/ui-bg_flat_95_fef1ec_40x100.png +0 -0
  30. data/app/assets/images/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  31. data/app/assets/images/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  32. data/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  33. data/app/assets/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  34. data/app/assets/images/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  35. data/app/assets/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  36. data/app/assets/images/ui-icons_217bc0_256x240.png +0 -0
  37. data/app/assets/images/ui-icons_222222_256x240.png +0 -0
  38. data/app/assets/images/ui-icons_2e83ff_256x240.png +0 -0
  39. data/app/assets/images/ui-icons_454545_256x240.png +0 -0
  40. data/app/assets/images/ui-icons_469bdd_256x240.png +0 -0
  41. data/app/assets/images/ui-icons_6da8d5_256x240.png +0 -0
  42. data/app/assets/images/ui-icons_888888_256x240.png +0 -0
  43. data/app/assets/images/ui-icons_cd0a0a_256x240.png +0 -0
  44. data/app/assets/images/ui-icons_d8e7f3_256x240.png +0 -0
  45. data/app/assets/images/ui-icons_f9bd01_256x240.png +0 -0
  46. data/app/assets/javascripts/add_taxonomy.js.erb +307 -0
  47. data/app/assets/javascripts/admin_invoices.js +15 -0
  48. data/app/assets/javascripts/api/v1/clients.js.coffee +3 -0
  49. data/app/assets/javascripts/api/v1/tokens.js.coffee +3 -0
  50. data/app/assets/javascripts/application.js.erb +25 -0
  51. data/app/assets/javascripts/bootstrap-dropdown.js +92 -0
  52. data/app/assets/javascripts/bootstrap-tabs.js +80 -0
  53. data/app/assets/javascripts/bootstrap.js.coffee +4 -0
  54. data/app/assets/javascripts/calendar.js +25 -0
  55. data/app/assets/javascripts/chosen.jquery.js +898 -0
  56. data/app/assets/javascripts/client_login/clients.js.coffee +3 -0
  57. data/app/assets/javascripts/client_login/reports.js.coffee +3 -0
  58. data/app/assets/javascripts/comments.js +16 -0
  59. data/app/assets/javascripts/css_browser_selector.js +8 -0
  60. data/app/assets/javascripts/dashboard.js +3 -0
  61. data/app/assets/javascripts/data_vaults.js.coffee +3 -0
  62. data/app/assets/javascripts/file_attachments.js +9 -0
  63. data/app/assets/javascripts/jquery-tagselector.js +50 -0
  64. data/app/assets/javascripts/jquery-ui-1.8.16.custom.min.js +791 -0
  65. data/app/assets/javascripts/jquery.jeditable.js +543 -0
  66. data/app/assets/javascripts/jquery_ujs.js +336 -0
  67. data/app/assets/javascripts/schedule_modal.js +25 -0
  68. data/app/assets/javascripts/specify_project.js +21 -0
  69. data/app/assets/javascripts/ticket_board.js +104 -0
  70. data/app/assets/stylesheets/_jquery-ui-1.8.16.custom.css +568 -0
  71. data/app/assets/stylesheets/application.css +7 -0
  72. data/app/assets/stylesheets/bootstrap_and_overrides.css.scss +41 -0
  73. data/app/assets/stylesheets/chosen.css +367 -0
  74. data/app/assets/stylesheets/client_login/clients.css.scss +3 -0
  75. data/app/assets/stylesheets/client_login/reports.css.scss +3 -0
  76. data/app/assets/stylesheets/data_vaults.css.scss +3 -0
  77. data/app/assets/stylesheets/jquery-tagselector.css +49 -0
  78. data/app/assets/stylesheets/responsive.scss +650 -0
  79. data/app/assets/stylesheets/screen.scss +303 -0
  80. data/app/controllers/admin/base_controller.rb +18 -0
  81. data/app/controllers/admin/invoices_controller.rb +42 -0
  82. data/app/controllers/admin/payroll_controller.rb +29 -0
  83. data/app/controllers/admin/site_settings_controller.rb +19 -0
  84. data/app/controllers/admin/unentered_time_report_controller.rb +26 -0
  85. data/app/controllers/admin/users_controller.rb +86 -0
  86. data/app/controllers/admin/weekly_time_report_controller.rb +11 -0
  87. data/app/controllers/api/base_controller.rb +14 -0
  88. data/app/controllers/api/v1/base_controller.rb +2 -0
  89. data/app/controllers/api/v1/clients_controller.rb +10 -0
  90. data/app/controllers/api/v1/credentials_controller.rb +10 -0
  91. data/app/controllers/api/v1/projects_controller.rb +27 -0
  92. data/app/controllers/api/v1/tickets_controller.rb +46 -0
  93. data/app/controllers/api/v1/tokens_controller.rb +30 -0
  94. data/app/controllers/api/v1/work_units_controller.rb +23 -0
  95. data/app/controllers/client_login/base_controller.rb +3 -0
  96. data/app/controllers/client_login/clients_controller.rb +35 -0
  97. data/app/controllers/client_login/contacts_controller.rb +53 -0
  98. data/app/controllers/client_login/projects_controller.rb +24 -0
  99. data/app/controllers/client_login/reports_controller.rb +23 -0
  100. data/app/controllers/client_login/tickets_controller.rb +41 -0
  101. data/app/controllers/client_login/work_units_controller.rb +11 -0
  102. data/app/controllers/clients_controller.rb +103 -0
  103. data/app/controllers/comments_controller.rb +75 -0
  104. data/app/controllers/contacts_controller.rb +54 -0
  105. data/app/controllers/dashboard/base_controller.rb +79 -0
  106. data/app/controllers/data_vaults_controller.rb +12 -0
  107. data/app/controllers/doorkeeper/application_controller.rb +33 -0
  108. data/app/controllers/file_attachments_controller.rb +60 -0
  109. data/app/controllers/projects_controller.rb +62 -0
  110. data/app/controllers/tickets_controller.rb +48 -0
  111. data/app/controllers/users_controller.rb +57 -0
  112. data/app/controllers/work_units_controller.rb +114 -0
  113. data/app/controllers/xrono/application_controller.rb +65 -0
  114. data/app/helpers/admin/unentered_time_report_helper.rb +9 -0
  115. data/app/helpers/admin_base_helper.rb +14 -0
  116. data/app/helpers/clients_helper.rb +5 -0
  117. data/app/helpers/dashboard_helper.rb +9 -0
  118. data/app/helpers/gravatar_helper.rb +5 -0
  119. data/app/helpers/refurl_helper.rb +9 -0
  120. data/app/helpers/xrono/application_helper.rb +54 -0
  121. data/app/mailers/notifier.rb +18 -0
  122. data/app/models/chart_data.rb +20 -0
  123. data/app/models/client.rb +98 -0
  124. data/app/models/comment.rb +8 -0
  125. data/app/models/contact.rb +10 -0
  126. data/app/models/data_vault.rb +6 -0
  127. data/app/models/file_attachment.rb +8 -0
  128. data/app/models/project.rb +76 -0
  129. data/app/models/role.rb +3 -0
  130. data/app/models/roles_user.rb +4 -0
  131. data/app/models/site_settings.rb +4 -0
  132. data/app/models/ticket.rb +85 -0
  133. data/app/models/user.rb +147 -0
  134. data/app/models/weekly_time_report.rb +26 -0
  135. data/app/models/work_unit.rb +99 -0
  136. data/app/models/work_unit/finders.rb +67 -0
  137. data/app/views/admin/_nav.html.haml +1 -0
  138. data/app/views/admin/base/index.html.haml +3 -0
  139. data/app/views/admin/base/reports.html.haml +3 -0
  140. data/app/views/admin/invoices/index.html.haml +19 -0
  141. data/app/views/admin/invoices/show.html.haml +57 -0
  142. data/app/views/admin/payroll/index.html.haml +18 -0
  143. data/app/views/admin/payroll/show.html.haml +56 -0
  144. data/app/views/admin/site_settings/edit.html.haml +32 -0
  145. data/app/views/admin/unentered_time_report/_week_navigation.html.haml +6 -0
  146. data/app/views/admin/unentered_time_report/show.html.haml +16 -0
  147. data/app/views/admin/users/_form.html.haml +48 -0
  148. data/app/views/admin/users/_locked_users.html.haml +31 -0
  149. data/app/views/admin/users/_users_table.html.haml +25 -0
  150. data/app/views/admin/users/edit.html.haml +1 -0
  151. data/app/views/admin/users/index.html.haml +14 -0
  152. data/app/views/admin/users/locked_clients.html.haml +13 -0
  153. data/app/views/admin/users/locked_users.html.haml +13 -0
  154. data/app/views/admin/users/new.html.haml +1 -0
  155. data/app/views/admin/users/projects.html.haml +25 -0
  156. data/app/views/admin/users/unlocked_clients.html.haml +13 -0
  157. data/app/views/admin/weekly_time_report/_week_pagination.html.haml +11 -0
  158. data/app/views/admin/weekly_time_report/show.html.haml +41 -0
  159. data/app/views/client_login/_work_unit_index.haml +16 -0
  160. data/app/views/client_login/base/index.html.haml +18 -0
  161. data/app/views/client_login/clients/show.html.haml +32 -0
  162. data/app/views/client_login/contacts/_form.html.haml +34 -0
  163. data/app/views/client_login/contacts/edit.html.haml +4 -0
  164. data/app/views/client_login/contacts/index.html.haml +30 -0
  165. data/app/views/client_login/contacts/new.html.haml +5 -0
  166. data/app/views/client_login/contacts/show.html.haml +26 -0
  167. data/app/views/client_login/projects/_tickets.html.haml +31 -0
  168. data/app/views/client_login/projects/show.html.haml +8 -0
  169. data/app/views/client_login/reports/index.html.haml +4 -0
  170. data/app/views/client_login/reports/work_units.html.haml +96 -0
  171. data/app/views/client_login/tickets/_form.html.haml +33 -0
  172. data/app/views/client_login/tickets/new.html.haml +1 -0
  173. data/app/views/client_login/tickets/show.html.haml +23 -0
  174. data/app/views/client_login/work_units/show.html.haml +18 -0
  175. data/app/views/clients/_breadcrumbs.html.haml +2 -0
  176. data/app/views/clients/_clients_table.html.haml +24 -0
  177. data/app/views/clients/_form.html.haml +34 -0
  178. data/app/views/clients/_projects.html.haml +31 -0
  179. data/app/views/clients/edit.html.haml +1 -0
  180. data/app/views/clients/inactive_clients.html.haml +9 -0
  181. data/app/views/clients/index.html.haml +8 -0
  182. data/app/views/clients/new.html.haml +1 -0
  183. data/app/views/clients/show.html.haml +34 -0
  184. data/app/views/clients/suspended_clients.html.haml +8 -0
  185. data/app/views/comments/_comment.html.haml +46 -0
  186. data/app/views/comments/_comment_form.haml +29 -0
  187. data/app/views/comments/_comments.html.haml +3 -0
  188. data/app/views/contacts/_form.html.haml +34 -0
  189. data/app/views/contacts/edit.html.haml +1 -0
  190. data/app/views/contacts/index.html.haml +23 -0
  191. data/app/views/contacts/new.html.haml +1 -0
  192. data/app/views/contacts/show.html.haml +26 -0
  193. data/app/views/dashboard/base/_two_week_time_report.html.haml +13 -0
  194. data/app/views/dashboard/base/_week_pagination.html.haml +10 -0
  195. data/app/views/dashboard/base/calendar.html.haml +1 -0
  196. data/app/views/dashboard/base/calendar.js.erb +3 -0
  197. data/app/views/dashboard/base/index.html.haml +18 -0
  198. data/app/views/devise/confirmations/new.html.haml +9 -0
  199. data/app/views/devise/mailer/confirmation_instructions.html.haml +4 -0
  200. data/app/views/devise/mailer/reset_password_instructions.html.haml +6 -0
  201. data/app/views/devise/mailer/unlock_instructions.html.haml +5 -0
  202. data/app/views/devise/passwords/edit.html.haml +17 -0
  203. data/app/views/devise/passwords/new.html.haml +12 -0
  204. data/app/views/devise/registrations/edit.html.haml +36 -0
  205. data/app/views/devise/registrations/new.html.haml +32 -0
  206. data/app/views/devise/sessions/new.html.haml +22 -0
  207. data/app/views/devise/shared/_links.haml +15 -0
  208. data/app/views/devise/unlocks/new.html.haml +9 -0
  209. data/app/views/file_attachments/_file_attachment.html.haml +10 -0
  210. data/app/views/file_attachments/_file_attachment_combined.html.haml +30 -0
  211. data/app/views/file_attachments/_file_attachments.html.haml +5 -0
  212. data/app/views/file_attachments/new.html.haml +17 -0
  213. data/app/views/layouts/application.html.haml +32 -0
  214. data/app/views/layouts/doorkeeper.html.haml +31 -0
  215. data/app/views/notifier/daily.text.erb +8 -0
  216. data/app/views/notifier/work_unit_notification.text.erb +17 -0
  217. data/app/views/projects/_breadcrumbs.html.haml +5 -0
  218. data/app/views/projects/_form.html.haml +94 -0
  219. data/app/views/projects/_pie_chart_metrics.html.haml +4 -0
  220. data/app/views/projects/_specify.html.haml +11 -0
  221. data/app/views/projects/_ticket_table.html.haml +36 -0
  222. data/app/views/projects/edit.html.haml +2 -0
  223. data/app/views/projects/new.html.haml +2 -0
  224. data/app/views/projects/show.html.haml +57 -0
  225. data/app/views/shared/_calendar.html.haml +86 -0
  226. data/app/views/shared/_data_vault.html.haml +16 -0
  227. data/app/views/shared/_files_and_comments.html.haml +21 -0
  228. data/app/views/shared/_flashes.html.haml +10 -0
  229. data/app/views/shared/_javascripts.html.haml +8 -0
  230. data/app/views/shared/_menu.html.haml +14 -0
  231. data/app/views/shared/_user_roles.html.haml +7 -0
  232. data/app/views/shared/_work_unit_index.html.haml +24 -0
  233. data/app/views/tickets/_add_ticket.html.haml +27 -0
  234. data/app/views/tickets/_breadcrumbs.html.haml +8 -0
  235. data/app/views/tickets/_form.html.haml +40 -0
  236. data/app/views/tickets/_ticket_detail.html.haml +18 -0
  237. data/app/views/tickets/edit.html.haml +2 -0
  238. data/app/views/tickets/modal_new.html.haml +28 -0
  239. data/app/views/tickets/new.html.haml +1 -0
  240. data/app/views/tickets/show.html.haml +28 -0
  241. data/app/views/tickets/ticket_detail.html.haml +18 -0
  242. data/app/views/users/_change_password_form.haml +13 -0
  243. data/app/views/users/_user_head.html.haml +7 -0
  244. data/app/views/users/edit.haml +34 -0
  245. data/app/views/users/historical_time.html.haml +5 -0
  246. data/app/views/users/index.html.haml +18 -0
  247. data/app/views/users/show.html.haml +13 -0
  248. data/app/views/work_units/_add_work_unit.html.haml +81 -0
  249. data/app/views/work_units/_breadcrumbs.html.haml +11 -0
  250. data/app/views/work_units/_dashboard_line.html.haml +6 -0
  251. data/app/views/work_units/_edit_work_unit.haml +44 -0
  252. data/app/views/work_units/_shared_form.haml +40 -0
  253. data/app/views/work_units/edit.html.haml +2 -0
  254. data/app/views/work_units/index.html.haml +7 -0
  255. data/app/views/work_units/new.html.haml +6 -0
  256. data/app/views/work_units/show.html.haml +25 -0
  257. data/app/workers/daily_notifier_worker.rb +7 -0
  258. data/app/workers/work_unit_notifier_worker.rb +7 -0
  259. data/config.ru +7 -0
  260. data/config/admin_navigation.rb +71 -0
  261. data/config/admin_reports_navigation.rb +6 -0
  262. data/config/boot.rb +6 -0
  263. data/config/client_navigation.rb +64 -0
  264. data/config/cucumber.yml +8 -0
  265. data/config/initializers/00_requirements.rb +2 -0
  266. data/config/initializers/backtrace_silencers.rb +7 -0
  267. data/config/initializers/devise.rb +144 -0
  268. data/config/initializers/doorkeeper.rb +32 -0
  269. data/config/initializers/doorkeeper_monkeypatch.rb +66 -0
  270. data/config/initializers/github_concern.rb +4 -0
  271. data/config/initializers/haml.rb +13 -0
  272. data/config/initializers/inflections.rb +10 -0
  273. data/config/initializers/load_controller_mixins.rb +1 -0
  274. data/config/initializers/mime_types.rb +5 -0
  275. data/config/initializers/paper_clip.rb +1 -0
  276. data/config/initializers/simple_navigation.rb +1 -0
  277. data/config/initializers/wrap_parameters.rb +14 -0
  278. data/config/locales/devise.en.yml +39 -0
  279. data/config/locales/doorkeeper.en.yml +23 -0
  280. data/config/locales/en.yml +201 -0
  281. data/config/locales/faker.en.yml +48 -0
  282. data/config/navigation.rb +78 -0
  283. data/config/rackspace_cloudfiles.yml +14 -0
  284. data/config/routes.rb +113 -0
  285. data/config/secondary_navigation.rb +65 -0
  286. data/config/trinidad.yml +4 -0
  287. data/config/warble.rb +144 -0
  288. data/db/migrate/20100825165612_create_clients.rb +14 -0
  289. data/db/migrate/20100825185313_create_projects.rb +14 -0
  290. data/db/migrate/20100825223943_create_tickets.rb +16 -0
  291. data/db/migrate/20100902174920_create_work_units.rb +14 -0
  292. data/db/migrate/20100902190129_add_missing_fields_to_work_units.rb +13 -0
  293. data/db/migrate/20100904173839_add_guid_to_clients_projects_tickets_and_work_orders.rb +13 -0
  294. data/db/migrate/20100922181642_create_comments.rb +19 -0
  295. data/db/migrate/20100927180254_devise_create_users.rb +32 -0
  296. data/db/migrate/20100927184505_add_details_to_users.rb +13 -0
  297. data/db/migrate/20100927191329_add_user_to_work_units.rb +9 -0
  298. data/db/migrate/20100928163356_create_roles.rb +22 -0
  299. data/db/migrate/20100928203745_create_addresses.rb +19 -0
  300. data/db/migrate/20100928204544_create_contacts.rb +17 -0
  301. data/db/migrate/20101007175626_add_lockable_to_users.rb +11 -0
  302. data/db/migrate/20101020162216_add_paid_at_to_work_units_table.rb +9 -0
  303. data/db/migrate/20101020162516_add_check_number_to_work_units_table.rb +9 -0
  304. data/db/migrate/20101020215135_add_paid_field_to_work_units_table.rb +9 -0
  305. data/db/migrate/20101020215226_add_invoiced_field_to_work_units_table.rb +9 -0
  306. data/db/migrate/20101020215457_remove_paid_at_from_work_units_table.rb +9 -0
  307. data/db/migrate/20101020215624_remove_check_number_from_work_units_table.rb +9 -0
  308. data/db/migrate/20101025161443_add_invoiced_at_to_work_units_table.rb +9 -0
  309. data/db/migrate/20101026151900_add_initials_to_clients.rb +9 -0
  310. data/db/migrate/20101029145059_create_file_attachments.rb +18 -0
  311. data/db/migrate/20101030142615_add_guid_to_users.rb +9 -0
  312. data/db/migrate/20101102145137_add_paid_at_to_work_units.rb +9 -0
  313. data/db/migrate/20101112151337_add_active_to_comments.rb +9 -0
  314. data/db/migrate/20101119172727_add_recieves_email_to_contact.rb +10 -0
  315. data/db/migrate/20101122225423_projects_users.rb +11 -0
  316. data/db/migrate/20101129214537_remove_projects_users_table.rb +11 -0
  317. data/db/migrate/20101130225328_contact_receives_email.rb +9 -0
  318. data/db/migrate/20101202203051_add_address_to_contacts.rb +19 -0
  319. data/db/migrate/20101202214746_remove_address_table.rb +17 -0
  320. data/db/migrate/20101216214304_add_hours_type_to_work_unit.rb +9 -0
  321. data/db/migrate/20101217152455_add_effective_hours_to_work_units.rb +9 -0
  322. data/db/migrate/20101228154820_add_overtime_multiplier_to_clients_table.rb +9 -0
  323. data/db/migrate/20101228154951_add_overtime_multiplier_to_projects_table.rb +9 -0
  324. data/db/migrate/20101228155122_create_site_settings_table.rb +11 -0
  325. data/db/migrate/20110107190927_add_site_logo_columns_to_site_settings.rb +15 -0
  326. data/db/migrate/20110111155513_add_total_yearly_pto_per_user_to_site_settings.rb +9 -0
  327. data/db/migrate/20110111220015_add_not_valid_to_file_attachment.rb +9 -0
  328. data/db/migrate/20110125153818_add_fullwidth_to_users.rb +9 -0
  329. data/db/migrate/20110222162404_add_daily_target_hours_to_users.rb +9 -0
  330. data/db/migrate/20110310021732_add_client_to_site_settings.rb +9 -0
  331. data/db/migrate/20110630194044_add_expanded_calendar_to_user.rb +9 -0
  332. data/db/migrate/20110922175742_add_state_to_tickets.rb +9 -0
  333. data/db/migrate/20111212193345_add_estimated_hours_to_tickets.rb +5 -0
  334. data/db/migrate/20111216152557_add_client_boolean_to_user.rb +5 -0
  335. data/db/migrate/20111220193307_add_repo_and_branch_to_projects_and_ticket.rb +6 -0
  336. data/db/migrate/20111220193619_create_git_pushes.rb +9 -0
  337. data/db/migrate/20111220193620_create_git_commits.rb +10 -0
  338. data/db/migrate/20111220193621_add_user_id_to_git_push.rb +5 -0
  339. data/db/migrate/20111220193622_create_github_concernable_git_pushes.rb +11 -0
  340. data/db/migrate/20111227140859_add_token_to_user.rb +7 -0
  341. data/db/migrate/20120102185406_add_completed_boolean_to_ticket.rb +5 -0
  342. data/db/migrate/20120104132121_add_completed_to_project.rb +5 -0
  343. data/db/migrate/20120124184915_modify_project_for_new_git_integration.rb +11 -0
  344. data/db/migrate/20120125145833_add_rates_to_project.rb +6 -0
  345. data/db/migrate/20120126151009_create_data_vaults.rb +11 -0
  346. data/db/migrate/20120126151341_create_versions.rb +18 -0
  347. data/db/migrate/20120126154403_rename_column_data_to_encrypted_data.rb +8 -0
  348. data/db/migrate/20120221193022_add_index_to_user_id_on_work_units.rb +5 -0
  349. data/db/migrate/20120221195345_acts_as_taggable_on_migration.rb +30 -0
  350. data/db/migrate/20120320212313_remove_timestamps_from_roles_users_table.rb +11 -0
  351. data/db/migrate/20120710034831_create_doorkeeper_tables.rb +42 -0
  352. data/db/migrate/20121021122002_add_missing_indices.rb +21 -0
  353. data/doc/website/favicon.ico +0 -0
  354. data/doc/website/images/clock_box.png +0 -0
  355. data/doc/website/images/demo.png +0 -0
  356. data/doc/website/images/download.png +0 -0
  357. data/doc/website/images/fork_me.png +0 -0
  358. data/doc/website/images/lightbox-blank.gif +0 -0
  359. data/doc/website/images/lightbox-btn-close.gif +0 -0
  360. data/doc/website/images/lightbox-btn-next.gif +0 -0
  361. data/doc/website/images/lightbox-btn-prev.gif +0 -0
  362. data/doc/website/images/lightbox-ico-loading.gif +0 -0
  363. data/doc/website/images/main_bg.png +0 -0
  364. data/doc/website/images/nav_bg.png +0 -0
  365. data/doc/website/images/screen_1.png +0 -0
  366. data/doc/website/images/screen_2.png +0 -0
  367. data/doc/website/images/screen_3.png +0 -0
  368. data/doc/website/images/screen_4.png +0 -0
  369. data/doc/website/images/screen_5.png +0 -0
  370. data/doc/website/images/screen_6.png +0 -0
  371. data/doc/website/images/support.png +0 -0
  372. data/doc/website/images/thumb_1.png +0 -0
  373. data/doc/website/images/thumb_2.png +0 -0
  374. data/doc/website/images/thumb_3.png +0 -0
  375. data/doc/website/images/thumb_4.png +0 -0
  376. data/doc/website/images/thumb_5.png +0 -0
  377. data/doc/website/images/thumb_6.png +0 -0
  378. data/doc/website/images/xrono_logo.png +0 -0
  379. data/doc/website/index.html +274 -0
  380. data/doc/website/javascripts/application.js +18 -0
  381. data/doc/website/javascripts/greyscalebasic_regular.typeface.js +1 -0
  382. data/doc/website/javascripts/jquery.lightbox-0.5.min.js +42 -0
  383. data/doc/website/javascripts/jquery.min.js +32 -0
  384. data/doc/website/javascripts/jquery.tweet.js +181 -0
  385. data/doc/website/javascripts/typeface.js +873 -0
  386. data/doc/website/javascripts/verdana_regular.typeface.js +1 -0
  387. data/doc/website/stylesheets/jquery.lightbox.css +104 -0
  388. data/doc/website/stylesheets/jquery.tweet.css +38 -0
  389. data/doc/website/stylesheets/reset-fonts-grids.css +32 -0
  390. data/doc/website/stylesheets/screen.css +228 -0
  391. data/doc/xrono_dash.png +0 -0
  392. data/doc/xrono_ticket.png +0 -0
  393. data/features/admin/invoices.feature +37 -0
  394. data/features/admin/manage_users.feature +17 -0
  395. data/features/admin/payroll.feature +64 -0
  396. data/features/admin/roles.feature +9 -0
  397. data/features/admin/site_settings.feature +19 -0
  398. data/features/admin/unentered_time_report.feature +38 -0
  399. data/features/admin/weekly_time_report.feature +14 -0
  400. data/features/api/v1/clients_controller.feature +58 -0
  401. data/features/authorization-admin.feature +34 -0
  402. data/features/authorization-non-admin.feature +38 -0
  403. data/features/client_login.feature +15 -0
  404. data/features/collaborative_work_units.feature +112 -0
  405. data/features/daily_emails.feature +11 -0
  406. data/features/dashboard.feature +74 -0
  407. data/features/manage_clients.feature +116 -0
  408. data/features/manage_comments.feature +30 -0
  409. data/features/manage_contacts.feature +56 -0
  410. data/features/manage_file_attachments.feature +51 -0
  411. data/features/manage_projects.feature +92 -0
  412. data/features/manage_self.feature +48 -0
  413. data/features/manage_tickets.feature +74 -0
  414. data/features/manage_users.feature +76 -0
  415. data/features/manage_work_units.feature +115 -0
  416. data/features/mockups/images/asset-tracker-client-show.png +0 -0
  417. data/features/mockups/images/asset-tracker.png +0 -0
  418. data/features/mockups/images/ixi - asset tracker v3 homepage - no time entered modal.png +0 -0
  419. data/features/mockups/images/ixi - asset tracker v3 homepage - schedule on modal.png +0 -0
  420. data/features/mockups/images/ixi - asset tracker v3 homepage.png +0 -0
  421. data/features/mockups/ixi - asset tracker v3 homepage - no time entered modal.bmml +194 -0
  422. data/features/mockups/ixi - asset tracker v3 homepage - schedule on modal.bmml +208 -0
  423. data/features/mockups/ixi - asset tracker v3 homepage.bmml +172 -0
  424. data/features/project_assignment.feature +69 -0
  425. data/features/search_work_units.feature +38 -0
  426. data/features/step_definitions/calendar_expansion_steps.rb +7 -0
  427. data/features/step_definitions/client_login_steps.rb +8 -0
  428. data/features/step_definitions/client_steps.rb +29 -0
  429. data/features/step_definitions/comment_steps.rb +4 -0
  430. data/features/step_definitions/contact_steps.rb +22 -0
  431. data/features/step_definitions/debug_steps.rb +5 -0
  432. data/features/step_definitions/devise_steps.rb +26 -0
  433. data/features/step_definitions/email_steps.rb +74 -0
  434. data/features/step_definitions/file_attachment_steps.rb +8 -0
  435. data/features/step_definitions/modified_web_steps.rb +25 -0
  436. data/features/step_definitions/pickle_steps.rb +101 -0
  437. data/features/step_definitions/project_steps.rb +32 -0
  438. data/features/step_definitions/search_steps.rb +3 -0
  439. data/features/step_definitions/ticket_board_steps.rb +39 -0
  440. data/features/step_definitions/ticket_detail_steps.rb +9 -0
  441. data/features/step_definitions/ticket_steps.rb +12 -0
  442. data/features/step_definitions/unentered_time_report_steps.rb +3 -0
  443. data/features/step_definitions/user_steps.rb +43 -0
  444. data/features/step_definitions/web_steps.rb +274 -0
  445. data/features/step_definitions/weekly_time_report_steps.rb +7 -0
  446. data/features/step_definitions/work_unit_index_steps.rb +8 -0
  447. data/features/step_definitions/work_unit_steps.rb +39 -0
  448. data/features/support/email.rb +21 -0
  449. data/features/support/env.rb +80 -0
  450. data/features/support/paths.rb +96 -0
  451. data/features/support/pickle.rb +26 -0
  452. data/features/support/selectors.rb +51 -0
  453. data/features/support/xrono.rb +19 -0
  454. data/features/work_unit_notifier.feature +11 -0
  455. data/lib/controller_mixins.rb +5 -0
  456. data/lib/controller_mixins/authorization.rb +15 -0
  457. data/lib/controller_mixins/contacts.rb +37 -0
  458. data/lib/controller_mixins/generic.rb +15 -0
  459. data/lib/controller_mixins/tickets.rb +35 -0
  460. data/lib/controller_mixins/work_units.rb +13 -0
  461. data/lib/date_ext.rb +16 -0
  462. data/lib/guid_referenced.rb +19 -0
  463. data/lib/tasks/.gitkeep +0 -0
  464. data/lib/tasks/acts_as_commentable_tasks.rake +4 -0
  465. data/lib/tasks/cucumber.rake +65 -0
  466. data/lib/tasks/git_repo_tasks.rake +47 -0
  467. data/lib/tasks/notifications.rake +8 -0
  468. data/lib/tasks/paperclip_tasks.rake +79 -0
  469. data/lib/xrono.rb +1 -0
  470. data/lib/xrono/engine.rb +45 -0
  471. data/public/404.html +26 -0
  472. data/public/422.html +26 -0
  473. data/public/500.html +26 -0
  474. data/public/favicon.ico +0 -0
  475. data/public/favicon.psd +0 -0
  476. data/public/robots.txt +5 -0
  477. data/public/stylesheets/.gitkeep +0 -0
  478. data/public/stylesheets/ie.css +53 -0
  479. data/public/stylesheets/print.css +57 -0
  480. data/public/stylesheets/screen.css +182 -0
  481. data/script/cucumber +10 -0
  482. data/script/rails +6 -0
  483. data/spec/blueprints.rb +86 -0
  484. data/spec/controllers/api/v1/clients_controller_spec.rb +41 -0
  485. data/spec/controllers/api/v1/projects_controller_spec.rb +54 -0
  486. data/spec/controllers/api/v1/tickets_controller_spec.rb +122 -0
  487. data/spec/controllers/api/v1/tokens_controller_spec.rb +52 -0
  488. data/spec/controllers/client_login/clients_controller_spec.rb +5 -0
  489. data/spec/controllers/client_login/reports_controller_spec.rb +5 -0
  490. data/spec/controllers/data_vaults_controller_spec.rb +5 -0
  491. data/spec/internal/app/controllers/application_controller.rb +5 -0
  492. data/spec/internal/config/admin_navigation.rb +71 -0
  493. data/spec/internal/config/database.yml +14 -0
  494. data/spec/internal/config/database.yml.example +20 -0
  495. data/spec/internal/config/database.yml.mysql +20 -0
  496. data/spec/internal/config/database.yml.mysql.jruby +20 -0
  497. data/spec/internal/config/database.yml.postgres +20 -0
  498. data/spec/internal/config/database.yml.postgres.jruby +20 -0
  499. data/spec/internal/config/navigation.rb +80 -0
  500. data/spec/internal/config/routes.rb +3 -0
  501. data/spec/internal/config/secondary_navigation.rb +65 -0
  502. data/spec/internal/db/schema.rb +296 -0
  503. data/spec/internal/log/.gitignore +1 -0
  504. data/spec/internal/public/favicon.ico +0 -0
  505. data/spec/internal/public/system/attachment_files/2/original/tmp.txt +1 -0
  506. data/spec/internal/public/system/attachment_files/3/original/tmp.txt +1 -0
  507. data/spec/lib/date_ext_spec.rb +40 -0
  508. data/spec/mailers/notifier_spec.rb +9 -0
  509. data/spec/models/client_spec.rb +167 -0
  510. data/spec/models/contact_spec.rb +29 -0
  511. data/spec/models/data_vault_spec.rb +5 -0
  512. data/spec/models/project_spec.rb +115 -0
  513. data/spec/models/ticket_spec.rb +223 -0
  514. data/spec/models/user_spec.rb +258 -0
  515. data/spec/models/work_unit_spec.rb +467 -0
  516. data/spec/spec_helper.rb +44 -0
  517. data/spec/support/xrono/macros.rb +15 -0
  518. data/vendor/plugins/.gitkeep +0 -0
  519. data/xrono.gemspec +50 -0
  520. metadata +1209 -0
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ mount Xrono, at: '/'
3
+ end
@@ -0,0 +1,65 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Configures your navigation
3
+ SimpleNavigation::Configuration.run do |navigation|
4
+ # Specify a custom renderer if needed.
5
+ # The default renderer is SimpleNavigation::Renderer::List which renders HTML lists.
6
+ # The renderer can also be specified as option in the render_navigation call.
7
+ # navigation.renderer = Your::Custom::Renderer
8
+
9
+ # Specify the class that will be applied to active navigation items. Defaults to 'selected'
10
+ # navigation.selected_class = 'your_selected_class'
11
+
12
+ # Specify the class that will be applied to the current leaf of
13
+ # active navigation items. Defaults to 'simple-navigation-active-leaf'
14
+ # navigation.active_leaf_class = 'your_active_leaf_class'
15
+
16
+ # Item keys are normally added to list items as id.
17
+ # This setting turns that off
18
+ # navigation.autogenerate_item_ids = false
19
+
20
+ # You can override the default logic that is used to autogenerate the item ids.
21
+ # To do this, define a Proc which takes the key of the current item as argument.
22
+ # The example below would add a prefix to each key.
23
+ # navigation.id_generator = Proc.new {|key| "my-prefix-#{key}"}
24
+
25
+ # If you need to add custom html around item names, you can define a proc that will be called with the name you pass in to the navigation.
26
+ # The example below shows how to wrap items spans.
27
+ # navigation.name_generator = Proc.new {|name| "<span>#{name}</span>"}
28
+
29
+ # The auto highlight feature is turned on by default.
30
+ # This turns it off globally (for the whole plugin)
31
+ # navigation.auto_highlight = false
32
+
33
+ # Define the primary navigation
34
+ navigation.items do |primary|
35
+ # Add an item to the primary navigation. The following params apply:
36
+ # key - a symbol which uniquely defines your navigation item in the scope of the primary_navigation
37
+ # name - will be displayed in the rendered navigation. This can also be a call to your I18n-framework.
38
+ # url - the address that the generated item links to. You can also use url_helpers (named routes, restful routes helper, url_for etc.)
39
+ # options - can be used to specify attributes that will be included in the rendered navigation item (e.g. id, class etc.)
40
+ # some special options that can be set:
41
+ # :if - Specifies a proc to call to determine if the item should
42
+ # be rendered (e.g. <tt>:if => Proc.new { current_user.admin? }</tt>). The
43
+ # proc should evaluate to a true or false value and is evaluated in the context of the view.
44
+ # :unless - Specifies a proc to call to determine if the item should not
45
+ # be rendered (e.g. <tt>:unless => Proc.new { current_user.admin? }</tt>). The
46
+ # proc should evaluate to a true or false value and is evaluated in the context of the view.
47
+ # :method - Specifies the http-method for the generated link - default is :get.
48
+ # :highlights_on - if autohighlighting is turned off and/or you want to explicitly specify
49
+ # when the item should be highlighted, you can set a regexp which is matched
50
+ # against the current URI. You may also use a proc, or the symbol <tt>:subpath</tt>.
51
+ #
52
+ primary.item :edit_user, t(:edit_profile), edit_user_path(current_user)
53
+ primary.item :logout, t(:logout), destroy_user_session_path
54
+
55
+ primary.dom_class = 'dropdown-menu'
56
+
57
+ # you can also specify a css id or class to attach to this particular level
58
+ # works for all levels of the menu
59
+ # primary.dom_id = 'menu-id'
60
+ # primary.dom_class = 'menu-class'
61
+
62
+ # You can turn off auto highlighting for a specific level
63
+ # primary.auto_highlight = false
64
+ end
65
+ end
@@ -0,0 +1,296 @@
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 to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 20121021122002) do
15
+
16
+ create_table "clients", :force => true do |t|
17
+ t.string "name"
18
+ t.string "status"
19
+ t.datetime "created_at", :null => false
20
+ t.datetime "updated_at", :null => false
21
+ t.string "guid"
22
+ t.string "initials"
23
+ t.decimal "overtime_multiplier", :precision => 10, :scale => 2
24
+ end
25
+
26
+ create_table "comments", :force => true do |t|
27
+ t.string "title", :limit => 50, :default => ""
28
+ t.text "comment"
29
+ t.integer "commentable_id"
30
+ t.string "commentable_type"
31
+ t.integer "user_id"
32
+ t.datetime "created_at", :null => false
33
+ t.datetime "updated_at", :null => false
34
+ t.boolean "active"
35
+ end
36
+
37
+ add_index "comments", ["commentable_id"], :name => "index_comments_on_commentable_id"
38
+ add_index "comments", ["commentable_type"], :name => "index_comments_on_commentable_type"
39
+ add_index "comments", ["user_id"], :name => "index_comments_on_user_id"
40
+
41
+ create_table "contacts", :force => true do |t|
42
+ t.string "first_name"
43
+ t.string "last_name"
44
+ t.string "email_address"
45
+ t.string "phone_number"
46
+ t.integer "client_id"
47
+ t.datetime "created_at", :null => false
48
+ t.datetime "updated_at", :null => false
49
+ t.boolean "receives_email", :default => false
50
+ t.string "street"
51
+ t.string "city"
52
+ t.string "state"
53
+ t.string "zip"
54
+ t.string "county"
55
+ t.string "country"
56
+ end
57
+
58
+ add_index "contacts", ["client_id"], :name => "index_contacts_on_client_id"
59
+
60
+ create_table "data_vaults", :force => true do |t|
61
+ t.integer "data_vaultable_id"
62
+ t.string "data_vaultable_type"
63
+ t.text "encrypted_data"
64
+ t.datetime "created_at", :null => false
65
+ t.datetime "updated_at", :null => false
66
+ end
67
+
68
+ add_index "data_vaults", ["data_vaultable_id", "data_vaultable_type"], :name => "dv_poly_vaultable"
69
+
70
+ create_table "file_attachments", :force => true do |t|
71
+ t.integer "client_id"
72
+ t.integer "ticket_id"
73
+ t.integer "project_id"
74
+ t.string "attachment_file_file_name"
75
+ t.string "attachment_file_file_content_type"
76
+ t.integer "attachment_file_file_size"
77
+ t.datetime "created_at", :null => false
78
+ t.datetime "updated_at", :null => false
79
+ t.boolean "not_valid"
80
+ end
81
+
82
+ add_index "file_attachments", ["client_id"], :name => "index_file_attachments_on_client_id"
83
+ add_index "file_attachments", ["project_id"], :name => "index_file_attachments_on_project_id"
84
+ add_index "file_attachments", ["ticket_id"], :name => "index_file_attachments_on_ticket_id"
85
+
86
+ create_table "git_commits", :force => true do |t|
87
+ t.text "payload"
88
+ t.integer "git_push_id"
89
+ t.datetime "created_at", :null => false
90
+ t.datetime "updated_at", :null => false
91
+ end
92
+
93
+ add_index "git_commits", ["git_push_id"], :name => "index_git_commits_on_git_push_id"
94
+
95
+ create_table "git_pushes", :force => true do |t|
96
+ t.text "payload"
97
+ t.datetime "created_at", :null => false
98
+ t.datetime "updated_at", :null => false
99
+ t.integer "user_id"
100
+ end
101
+
102
+ add_index "git_pushes", ["user_id"], :name => "index_git_pushes_on_user_id"
103
+
104
+ create_table "github_concernable_git_pushes", :force => true do |t|
105
+ t.string "github_concernable_type"
106
+ t.integer "github_concernable_id"
107
+ t.integer "git_push_id"
108
+ t.datetime "created_at", :null => false
109
+ t.datetime "updated_at", :null => false
110
+ end
111
+
112
+ add_index "github_concernable_git_pushes", ["git_push_id"], :name => "gh_concern_push_id"
113
+ add_index "github_concernable_git_pushes", ["github_concernable_id", "github_concernable_type"], :name => "gh_concern_poly"
114
+
115
+ create_table "oauth_access_grants", :force => true do |t|
116
+ t.integer "resource_owner_id", :null => false
117
+ t.integer "application_id", :null => false
118
+ t.string "token", :null => false
119
+ t.integer "expires_in", :null => false
120
+ t.string "redirect_uri", :null => false
121
+ t.datetime "created_at", :null => false
122
+ t.datetime "revoked_at"
123
+ t.string "scopes"
124
+ end
125
+
126
+ add_index "oauth_access_grants", ["token"], :name => "index_oauth_access_grants_on_token", :unique => true
127
+
128
+ create_table "oauth_access_tokens", :force => true do |t|
129
+ t.integer "resource_owner_id"
130
+ t.integer "application_id", :null => false
131
+ t.string "token", :null => false
132
+ t.string "refresh_token"
133
+ t.integer "expires_in"
134
+ t.datetime "revoked_at"
135
+ t.datetime "created_at", :null => false
136
+ t.string "scopes"
137
+ end
138
+
139
+ add_index "oauth_access_tokens", ["refresh_token"], :name => "index_oauth_access_tokens_on_refresh_token", :unique => true
140
+ add_index "oauth_access_tokens", ["resource_owner_id"], :name => "index_oauth_access_tokens_on_resource_owner_id"
141
+ add_index "oauth_access_tokens", ["token"], :name => "index_oauth_access_tokens_on_token", :unique => true
142
+
143
+ create_table "oauth_applications", :force => true do |t|
144
+ t.string "name", :null => false
145
+ t.string "uid", :null => false
146
+ t.string "secret", :null => false
147
+ t.string "redirect_uri", :null => false
148
+ t.datetime "created_at", :null => false
149
+ t.datetime "updated_at", :null => false
150
+ end
151
+
152
+ add_index "oauth_applications", ["uid"], :name => "index_oauth_applications_on_uid", :unique => true
153
+
154
+ create_table "projects", :force => true do |t|
155
+ t.string "name"
156
+ t.integer "client_id"
157
+ t.datetime "created_at", :null => false
158
+ t.datetime "updated_at", :null => false
159
+ t.string "guid"
160
+ t.decimal "overtime_multiplier", :precision => 10, :scale => 2
161
+ t.string "git_repo_name"
162
+ t.boolean "completed", :default => false
163
+ t.string "git_repo_url"
164
+ t.text "release_notes"
165
+ t.text "xrono_notes"
166
+ t.string "rate_a"
167
+ t.string "rate_b"
168
+ end
169
+
170
+ add_index "projects", ["client_id"], :name => "index_projects_on_client_id"
171
+
172
+ create_table "roles", :force => true do |t|
173
+ t.string "name", :limit => 40
174
+ t.string "authorizable_type", :limit => 40
175
+ t.integer "authorizable_id"
176
+ t.datetime "created_at", :null => false
177
+ t.datetime "updated_at", :null => false
178
+ end
179
+
180
+ add_index "roles", ["authorizable_id", "authorizable_type"], :name => "roles_auth"
181
+
182
+ create_table "roles_users", :id => false, :force => true do |t|
183
+ t.integer "user_id"
184
+ t.integer "role_id"
185
+ end
186
+
187
+ add_index "roles_users", ["role_id"], :name => "index_roles_users_on_role_id"
188
+ add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
189
+
190
+ create_table "site_settings", :force => true do |t|
191
+ t.decimal "overtime_multiplier", :precision => 10, :scale => 2
192
+ t.string "site_logo_file_name"
193
+ t.string "site_logo_content_type"
194
+ t.integer "site_logo_file_size"
195
+ t.datetime "site_logo_updated_at"
196
+ t.decimal "total_yearly_pto_per_user", :precision => 10, :scale => 2
197
+ t.integer "client_id"
198
+ end
199
+
200
+ add_index "site_settings", ["client_id"], :name => "index_site_settings_on_client_id"
201
+
202
+ create_table "taggings", :force => true do |t|
203
+ t.integer "tag_id"
204
+ t.integer "taggable_id"
205
+ t.string "taggable_type"
206
+ t.integer "tagger_id"
207
+ t.string "tagger_type"
208
+ t.string "context", :limit => 128
209
+ t.datetime "created_at"
210
+ end
211
+
212
+ add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
213
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
214
+ add_index "taggings", ["tagger_id", "tagger_type"], :name => "taggings_tagger"
215
+
216
+ create_table "tags", :force => true do |t|
217
+ t.string "name"
218
+ end
219
+
220
+ create_table "tickets", :force => true do |t|
221
+ t.integer "project_id"
222
+ t.string "priority"
223
+ t.string "name"
224
+ t.text "description"
225
+ t.datetime "created_at", :null => false
226
+ t.datetime "updated_at", :null => false
227
+ t.string "guid"
228
+ t.string "state"
229
+ t.decimal "estimated_hours", :precision => 10, :scale => 2
230
+ t.string "git_branch"
231
+ t.boolean "completed", :default => false
232
+ end
233
+
234
+ add_index "tickets", ["project_id"], :name => "index_tickets_on_project_id"
235
+
236
+ create_table "users", :force => true do |t|
237
+ t.string "email", :default => "", :null => false
238
+ t.string "encrypted_password", :limit => 128, :default => "", :null => false
239
+ t.string "reset_password_token"
240
+ t.string "remember_token"
241
+ t.datetime "remember_created_at"
242
+ t.integer "sign_in_count", :default => 0
243
+ t.datetime "current_sign_in_at"
244
+ t.datetime "last_sign_in_at"
245
+ t.string "current_sign_in_ip"
246
+ t.string "last_sign_in_ip"
247
+ t.datetime "created_at", :null => false
248
+ t.datetime "updated_at", :null => false
249
+ t.string "first_name"
250
+ t.string "last_name"
251
+ t.string "middle_initial"
252
+ t.datetime "locked_at"
253
+ t.string "guid"
254
+ t.boolean "full_width", :default => false
255
+ t.integer "daily_target_hours"
256
+ t.boolean "expanded_calendar"
257
+ t.boolean "client", :default => false
258
+ t.string "authentication_token"
259
+ end
260
+
261
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
262
+ add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
263
+
264
+ create_table "versions", :force => true do |t|
265
+ t.string "item_type", :null => false
266
+ t.integer "item_id", :null => false
267
+ t.string "event", :null => false
268
+ t.string "whodunnit"
269
+ t.text "object"
270
+ t.datetime "created_at"
271
+ end
272
+
273
+ add_index "versions", ["item_type", "item_id"], :name => "index_versions_on_item_type_and_item_id"
274
+
275
+ create_table "work_units", :force => true do |t|
276
+ t.text "description"
277
+ t.integer "ticket_id"
278
+ t.datetime "created_at", :null => false
279
+ t.datetime "updated_at", :null => false
280
+ t.decimal "hours", :precision => 10, :scale => 2
281
+ t.boolean "overtime"
282
+ t.datetime "scheduled_at"
283
+ t.string "guid"
284
+ t.integer "user_id"
285
+ t.string "paid"
286
+ t.string "invoiced"
287
+ t.datetime "invoiced_at"
288
+ t.datetime "paid_at"
289
+ t.string "hours_type"
290
+ t.decimal "effective_hours", :precision => 10, :scale => 2
291
+ end
292
+
293
+ add_index "work_units", ["ticket_id"], :name => "index_work_units_on_ticket_id"
294
+ add_index "work_units", ["user_id"], :name => "index_work_units_on_user_id"
295
+
296
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Date do
4
+ let(:friday) { Date.parse('2010-10-15') }
5
+ let(:monday) { Date.parse('2010-10-18') }
6
+ let(:tuesday) { Date.parse('2010-10-19') }
7
+
8
+ context "when determining the previous working day" do
9
+
10
+ it "has a prev_working_day method" do
11
+ monday.respond_to?(:prev_working_day).should be true
12
+ end
13
+
14
+ it "returns monday when run on a tuesday" do
15
+ tuesday.prev_working_day.should == monday
16
+ end
17
+
18
+ it "returns friday when run on a monday" do
19
+ monday.prev_working_day.should == friday
20
+ end
21
+
22
+ end
23
+
24
+ context "when determining the next working day" do
25
+
26
+ it "has a next_working_day method" do
27
+ monday.respond_to?(:next_working_day).should be true
28
+ end
29
+
30
+ it "returns tuesday when run on a monday" do
31
+ monday.next_working_day.should == tuesday
32
+ end
33
+
34
+ it "returns monday when run on a friday" do
35
+ friday.next_working_day.should == monday
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,9 @@
1
+ require "spec_helper"
2
+
3
+ describe Notifier do
4
+
5
+ it "has the method to send work unit notifications" do
6
+ Notifier.respond_to?(:work_unit_notification).should be_true
7
+ end
8
+
9
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe Client do
4
+ let(:user) { User.make }
5
+ let(:client) { Client.make(:name => 'New Client', :status => 'Active') }
6
+ let(:project) { Project.make(:client => client) }
7
+ let(:ticket) { Ticket.make(:project => project) }
8
+ let(:work_unit1) { WorkUnit.make(:ticket => ticket) }
9
+ let(:work_unit2) { WorkUnit.make(:ticket => ticket) }
10
+ let(:work_unit3) { WorkUnit.make(:ticket => ticket) }
11
+
12
+ subject { client }
13
+
14
+ it { should have_many :projects }
15
+ it { should have_many(:tickets).through(:projects) }
16
+ it { should have_many :comments }
17
+ it { should have_many :file_attachments }
18
+ it { should have_many :contacts }
19
+
20
+ it { should validate_presence_of :name }
21
+ it { should validate_presence_of :status }
22
+ it { should validate_uniqueness_of :name }
23
+
24
+ describe '#to_s' do
25
+ subject { client.to_s }
26
+ it 'returns the client name' do
27
+ should == 'New Client'
28
+ end
29
+ end
30
+
31
+ describe '#allows_access?' do
32
+ subject { client.allows_access?(user) }
33
+
34
+ context 'when the user has access to one or more of its projects' do
35
+ before { user.has_role!(:developer, project) }
36
+ it { should be_true }
37
+ end
38
+
39
+ context 'when the user has access to none of its projects' do
40
+ before { user.has_no_roles_for!(project) }
41
+ it { should be_false }
42
+ end
43
+ end
44
+
45
+ describe '#uninvoiced_hours' do
46
+ subject { client.uninvoiced_hours }
47
+
48
+ context 'when there are invoiced and uninvoiced work units' do
49
+ before do
50
+ work_unit1.update_attributes(:hours => 1, :hours_type => 'Normal')
51
+ work_unit2.update_attributes(:hours => 1, :hours_type => 'Normal')
52
+ work_unit3.update_attributes(:hours => 1, :hours_type => 'Normal', :invoiced => '1', :invoiced_at => Date.current)
53
+ end
54
+
55
+ it 'returns the sum of the hours on the uninvoiced work units' do
56
+ should == 2
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#hours' do
62
+ subject { client.hours }
63
+
64
+ context 'when there are normal work units with hours' do
65
+ before do
66
+ work_unit1.update_attributes(:hours => 1, :hours_type => 'Normal')
67
+ work_unit2.update_attributes(:hours => 1, :hours_type => 'Normal')
68
+ end
69
+
70
+ it 'should return the correct sum of hours for those work units' do
71
+ should == 2
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '#tickets' do
77
+ subject { client.tickets }
78
+
79
+ context 'when the client has tickets' do
80
+ let(:ticket2) { Ticket.make(:project => project) }
81
+
82
+ it 'returns the collection of tickets that belong to the client' do
83
+ should =~ [ticket, ticket2]
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '.for_user' do
89
+ subject { Client.for_user user }
90
+
91
+ context 'when a user has access to projects of clients' do
92
+ before { user.has_role!(:developer, project) }
93
+
94
+ it 'returns a collection of clients to which the user has access' do
95
+ should == [client]
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '.for' do
101
+ let(:projects) { [project] }
102
+ let(:tickets) { [ticket] }
103
+ let(:work_units) { [work_unit1, work_unit2, work_unit3] }
104
+
105
+ context 'given a collection of projects' do
106
+ subject { Client.for projects }
107
+
108
+ it 'returns a unique list of clients for those projects' do
109
+ should == [client]
110
+ end
111
+ end
112
+
113
+ context 'given a collection of tickets' do
114
+ subject { Client.for tickets }
115
+
116
+ it 'returns a unique list of clients for those tickets' do
117
+ should == [client]
118
+ end
119
+ end
120
+
121
+ context 'given a collection of work units' do
122
+ subject { Client.for work_units }
123
+
124
+ it 'returns a unique list of clients for those work units' do
125
+ should == [client]
126
+ end
127
+ end
128
+ end
129
+
130
+ describe 'tickets' do
131
+ it 'should return the tickets for the client' do
132
+ client = Client.make
133
+ project = client.projects.make
134
+ ticket = project.tickets.make
135
+ ticket_2 = project.tickets.make
136
+ ticket_3 = Ticket.make
137
+ client.tickets.should =~ [ticket,ticket_2]
138
+ end
139
+ end
140
+
141
+ describe 'file_and_comments' do
142
+ let!(:file_attachment) {
143
+ FileAttachment.create!({
144
+ :client_id => client.id,
145
+ :ticket_id => ticket.id,
146
+ :project_id => project.id,
147
+ :attachment_file_file_name => "file.file",
148
+ :created_at => 2.days.ago
149
+ })
150
+ }
151
+
152
+ let!(:comment) {
153
+ Comment.create!({
154
+ :title => "Test",
155
+ :comment => "Herro",
156
+ :commentable_id => client.id,
157
+ :created_at => 1.hours.ago,
158
+ :commentable_type => "Client"
159
+ })
160
+ }
161
+
162
+ it 'adds file attachments and comments in the correct order' do
163
+ client.files_and_comments.should == [file_attachment, comment]
164
+ end
165
+ end
166
+ end
167
+