fat_free_crm 0.12.3 → 0.13.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.

Potentially problematic release.


This version of fat_free_crm might be problematic. Click here for more details.

Files changed (521) hide show
  1. checksums.yaml +5 -13
  2. data/.travis.yml +1 -11
  3. data/Gemfile +7 -19
  4. data/Gemfile.lock +166 -166
  5. data/Procfile +1 -1
  6. data/README.md +20 -20
  7. data/app/assets/javascripts/admin/fields.js.coffee +3 -3
  8. data/app/assets/javascripts/application.js.erb +3 -0
  9. data/app/assets/javascripts/crm.js +1 -0
  10. data/app/assets/javascripts/crm_comments.js.coffee +66 -0
  11. data/app/assets/javascripts/lists.js.coffee +45 -2
  12. data/app/assets/javascripts/search.js.coffee +2 -0
  13. data/app/assets/javascripts/timeago.js +17 -0
  14. data/app/assets/stylesheets/advanced_search.css.scss +49 -25
  15. data/app/assets/stylesheets/application.css.erb +3 -0
  16. data/app/assets/stylesheets/common.scss +13 -0
  17. data/app/assets/stylesheets/format_buttons.css.scss +15 -10
  18. data/app/assets/stylesheets/header.scss +3 -0
  19. data/app/assets/stylesheets/lists.css.scss +4 -0
  20. data/app/controllers/admin/fields_controller.rb +5 -5
  21. data/app/controllers/admin/users_controller.rb +1 -3
  22. data/app/controllers/application_controller.rb +23 -23
  23. data/app/controllers/comments_controller.rb +3 -31
  24. data/app/controllers/entities/accounts_controller.rb +3 -3
  25. data/app/controllers/entities/campaigns_controller.rb +4 -4
  26. data/app/controllers/entities/contacts_controller.rb +2 -2
  27. data/app/controllers/entities/leads_controller.rb +3 -3
  28. data/app/controllers/entities/opportunities_controller.rb +4 -3
  29. data/app/controllers/entities_controller.rb +6 -6
  30. data/app/controllers/home_controller.rb +1 -1
  31. data/app/controllers/lists_controller.rb +8 -1
  32. data/app/controllers/tasks_controller.rb +1 -1
  33. data/app/controllers/users_controller.rb +46 -23
  34. data/app/helpers/admin/application_helper.rb +1 -3
  35. data/app/helpers/admin/field_groups_helper.rb +2 -1
  36. data/app/helpers/application_helper.rb +37 -16
  37. data/app/helpers/home_helper.rb +1 -2
  38. data/app/helpers/leads_helper.rb +5 -6
  39. data/app/helpers/tasks_helper.rb +36 -50
  40. data/app/models/entities/account.rb +10 -7
  41. data/app/models/entities/campaign.rb +4 -4
  42. data/app/models/entities/contact.rb +8 -5
  43. data/app/models/entities/lead.rb +8 -8
  44. data/app/models/entities/opportunity.rb +13 -18
  45. data/app/models/fields/custom_field.rb +10 -0
  46. data/app/models/fields/field.rb +3 -3
  47. data/app/models/fields/field_group.rb +1 -1
  48. data/app/models/list.rb +1 -0
  49. data/app/models/polymorphic/address.rb +3 -3
  50. data/app/models/polymorphic/comment.rb +2 -4
  51. data/app/models/polymorphic/task.rb +32 -27
  52. data/app/models/setting.rb +3 -9
  53. data/app/models/users/ability.rb +2 -13
  54. data/app/models/users/user.rb +12 -15
  55. data/app/views/accounts/_edit.html.haml +1 -1
  56. data/app/views/accounts/_index_brief.html.haml +3 -3
  57. data/app/views/accounts/_index_long.html.haml +3 -3
  58. data/app/views/accounts/_new.html.haml +1 -1
  59. data/app/views/accounts/create.js.haml +17 -0
  60. data/app/views/accounts/destroy.js.haml +6 -0
  61. data/app/views/accounts/edit.js.haml +32 -0
  62. data/app/views/accounts/index.js.haml +11 -0
  63. data/app/views/accounts/index.xls.builder +9 -7
  64. data/app/views/accounts/new.js.haml +11 -0
  65. data/app/views/accounts/show.js.haml +5 -0
  66. data/app/views/accounts/update.js.haml +17 -0
  67. data/app/views/admin/field_groups/_edit.html.haml +1 -1
  68. data/app/views/admin/field_groups/_new.html.haml +1 -1
  69. data/app/views/admin/field_groups/confirm.js.haml +7 -0
  70. data/app/views/admin/field_groups/create.js.haml +20 -0
  71. data/app/views/admin/field_groups/destroy.js.haml +9 -0
  72. data/app/views/admin/field_groups/edit.js.haml +12 -0
  73. data/app/views/admin/field_groups/new.js.haml +8 -0
  74. data/app/views/admin/field_groups/update.js.haml +8 -0
  75. data/app/views/admin/fields/_field.html.haml +2 -2
  76. data/app/views/admin/fields/_form.html.haml +2 -2
  77. data/app/views/admin/fields/create.js.haml +17 -0
  78. data/app/views/admin/fields/destroy.js.haml +8 -0
  79. data/app/views/admin/fields/edit.js.haml +3 -0
  80. data/app/views/admin/fields/update.js.haml +13 -0
  81. data/app/views/admin/groups/_edit.html.haml +1 -1
  82. data/app/views/admin/groups/_new.html.haml +1 -1
  83. data/app/views/admin/groups/create.js.haml +10 -0
  84. data/app/views/admin/groups/destroy.js.haml +9 -0
  85. data/app/views/admin/groups/edit.js.haml +14 -0
  86. data/app/views/admin/groups/index.html.haml +1 -1
  87. data/app/views/admin/groups/index.js.haml +2 -0
  88. data/app/views/admin/groups/new.js.haml +9 -0
  89. data/app/views/admin/groups/update.js.haml +9 -0
  90. data/app/views/admin/tags/_edit.html.haml +1 -1
  91. data/app/views/admin/tags/_new.html.haml +1 -1
  92. data/app/views/admin/tags/confirm.js.haml +7 -0
  93. data/app/views/admin/tags/create.js.haml +11 -0
  94. data/app/views/admin/tags/destroy.js.haml +10 -0
  95. data/app/views/admin/tags/edit.js.haml +20 -0
  96. data/app/views/admin/tags/new.js.haml +7 -0
  97. data/app/views/admin/tags/update.js.haml +9 -0
  98. data/app/views/admin/users/_edit.html.haml +1 -1
  99. data/app/views/admin/users/_new.html.haml +1 -1
  100. data/app/views/admin/users/_user.html.haml +1 -1
  101. data/app/views/admin/users/confirm.js.haml +7 -0
  102. data/app/views/admin/users/create.js.haml +10 -0
  103. data/app/views/admin/users/destroy.js.haml +10 -0
  104. data/app/views/admin/users/edit.js.haml +20 -0
  105. data/app/views/admin/users/index.js.haml +2 -0
  106. data/app/views/admin/users/new.js.haml +9 -0
  107. data/app/views/admin/users/reactivate.js.haml +3 -0
  108. data/app/views/admin/users/suspend.js.haml +3 -0
  109. data/app/views/admin/users/update.js.haml +9 -0
  110. data/app/views/authentications/new.html.haml +1 -1
  111. data/app/views/campaigns/_edit.html.haml +1 -1
  112. data/app/views/campaigns/_new.html.haml +1 -1
  113. data/app/views/campaigns/create.js.haml +20 -0
  114. data/app/views/campaigns/destroy.js.haml +6 -0
  115. data/app/views/campaigns/edit.js.haml +33 -0
  116. data/app/views/campaigns/index.js.haml +11 -0
  117. data/app/views/campaigns/index.xls.builder +9 -7
  118. data/app/views/campaigns/new.js.haml +11 -0
  119. data/app/views/campaigns/show.js.haml +5 -0
  120. data/app/views/campaigns/update.js.haml +20 -0
  121. data/app/views/comments/_comment.html.haml +1 -1
  122. data/app/views/comments/_edit.html.haml +1 -1
  123. data/app/views/comments/_new.html.haml +3 -2
  124. data/app/views/comments/create.js.haml +14 -0
  125. data/app/views/comments/destroy.js.haml +5 -0
  126. data/app/views/comments/edit.js.haml +11 -0
  127. data/app/views/comments/update.js.haml +9 -0
  128. data/app/views/contacts/_edit.html.haml +1 -1
  129. data/app/views/contacts/_index_full.html.haml +1 -1
  130. data/app/views/contacts/_index_long.html.haml +2 -1
  131. data/app/views/contacts/_new.html.haml +1 -1
  132. data/app/views/contacts/_section_general.html.haml +3 -3
  133. data/app/views/contacts/create.js.haml +23 -0
  134. data/app/views/contacts/destroy.js.haml +9 -0
  135. data/app/views/contacts/edit.js.haml +35 -0
  136. data/app/views/contacts/index.js.haml +11 -0
  137. data/app/views/contacts/index.xls.builder +9 -7
  138. data/app/views/contacts/new.js.haml +13 -0
  139. data/app/views/contacts/show.js.haml +5 -0
  140. data/app/views/contacts/update.js.haml +22 -0
  141. data/app/views/emails/destroy.js.haml +5 -0
  142. data/app/views/entities/_permissions.html.haml +1 -1
  143. data/app/views/entities/attach.js.haml +21 -0
  144. data/app/views/entities/contacts.js.haml +3 -0
  145. data/app/views/entities/discard.js.haml +6 -0
  146. data/app/views/entities/leads.js.haml +3 -0
  147. data/app/views/entities/opportunities.js.haml +3 -0
  148. data/app/views/entities/subscription_update.js.haml +4 -0
  149. data/app/views/entities/versions.js.haml +3 -0
  150. data/app/views/fields/group.js.erb +3 -0
  151. data/app/views/home/_account.html.haml +3 -3
  152. data/app/views/home/_opportunity.html.haml +3 -3
  153. data/app/views/home/index.atom.builder +3 -3
  154. data/app/views/home/index.js.haml +7 -0
  155. data/app/views/home/index.rss.builder +2 -2
  156. data/app/views/home/options.js.haml +7 -0
  157. data/app/views/layouts/_footer.html.haml +0 -4
  158. data/app/views/layouts/_sidebar.html.haml +1 -0
  159. data/app/views/layouts/_tabbed.html.haml +1 -4
  160. data/app/views/layouts/admin/application.html.haml +0 -1
  161. data/app/views/layouts/application.html.haml +5 -7
  162. data/app/views/leads/_convert.html.haml +1 -1
  163. data/app/views/leads/_edit.html.haml +1 -1
  164. data/app/views/leads/_index_long.html.haml +2 -2
  165. data/app/views/leads/_new.html.haml +1 -1
  166. data/app/views/leads/convert.js.haml +35 -0
  167. data/app/views/leads/create.js.haml +21 -0
  168. data/app/views/leads/destroy.js.haml +9 -0
  169. data/app/views/leads/edit.js.haml +35 -0
  170. data/app/views/leads/index.js.haml +11 -0
  171. data/app/views/leads/index.xls.builder +9 -7
  172. data/app/views/leads/new.js.haml +11 -0
  173. data/app/views/leads/promote.js.haml +26 -0
  174. data/app/views/leads/reject.js.haml +12 -0
  175. data/app/views/leads/show.js.haml +5 -0
  176. data/app/views/leads/update.js.haml +26 -0
  177. data/app/views/lists/_personal_sidebar.html.haml +28 -0
  178. data/app/views/lists/_sidebar.html.haml +10 -7
  179. data/app/views/lists/create.js.haml +10 -0
  180. data/app/views/lists/destroy.js.haml +1 -0
  181. data/app/views/opportunities/_edit.html.haml +1 -1
  182. data/app/views/opportunities/_index_brief.html.haml +3 -3
  183. data/app/views/opportunities/_index_long.html.haml +3 -3
  184. data/app/views/opportunities/_new.html.haml +1 -2
  185. data/app/views/opportunities/_top_section.html.haml +4 -0
  186. data/app/views/opportunities/contacts.js.haml +3 -0
  187. data/app/views/opportunities/create.js.haml +29 -0
  188. data/app/views/opportunities/destroy.js.haml +13 -0
  189. data/app/views/opportunities/edit.js.haml +35 -0
  190. data/app/views/opportunities/index.js.haml +11 -0
  191. data/app/views/opportunities/index.xls.builder +9 -7
  192. data/app/views/opportunities/new.js.haml +13 -0
  193. data/app/views/opportunities/show.js.haml +5 -0
  194. data/app/views/opportunities/update.js.haml +25 -0
  195. data/app/views/passwords/edit.html.haml +1 -1
  196. data/app/views/passwords/new.html.haml +1 -1
  197. data/app/views/shared/_comment.html.haml +1 -1
  198. data/app/views/shared/_inline_styles.html.haml +1 -1
  199. data/app/views/tasks/_edit.html.haml +1 -1
  200. data/app/views/tasks/_new.html.haml +1 -1
  201. data/app/views/tasks/complete.js.haml +14 -0
  202. data/app/views/tasks/create.js.haml +39 -0
  203. data/app/views/tasks/destroy.js.haml +7 -0
  204. data/app/views/tasks/discard.js.haml +1 -0
  205. data/app/views/tasks/edit.js.haml +26 -0
  206. data/app/views/tasks/filter.js.haml +4 -0
  207. data/app/views/tasks/index.xls.builder +7 -5
  208. data/app/views/tasks/new.js.haml +8 -0
  209. data/app/views/tasks/update.js.haml +19 -0
  210. data/app/views/users/_password.html.haml +1 -1
  211. data/app/views/users/_profile.html.haml +1 -1
  212. data/app/views/users/avatar.js.haml +9 -0
  213. data/app/views/users/change_password.js.haml +13 -0
  214. data/app/views/users/edit.js.haml +9 -0
  215. data/app/views/users/new.html.haml +1 -1
  216. data/app/views/users/password.js.haml +10 -0
  217. data/app/views/users/update.js.haml +9 -0
  218. data/app/views/users/upload_avatar.js.haml +7 -0
  219. data/app/views/versions/_version.html.haml +1 -1
  220. data/config/application.rb +1 -4
  221. data/config/environments/production.rb +3 -2
  222. data/config/initializers/custom_field_ransack_translations.rb +15 -0
  223. data/config/initializers/locale.rb +9 -1
  224. data/config/initializers/secret_token.rb +1 -25
  225. data/config/initializers/views.rb +20 -20
  226. data/config/locales/cz.yml +245 -211
  227. data/config/locales/cz_fat_free_crm.yml +105 -181
  228. data/config/locales/de.yml +162 -118
  229. data/config/locales/de_fat_free_crm.yml +760 -731
  230. data/config/locales/de_ransack.yml +91 -0
  231. data/config/locales/en-GB.yml +158 -119
  232. data/config/locales/en-GB_fat_free_crm.yml +161 -279
  233. data/config/locales/en-US.yml +158 -121
  234. data/config/locales/en-US_fat_free_crm.yml +185 -179
  235. data/config/locales/en-US_ransack.yml +81 -82
  236. data/config/locales/es.yml +164 -123
  237. data/config/locales/es_fat_free_crm.yml +151 -209
  238. data/config/locales/fr-CA.yml +167 -130
  239. data/config/locales/fr-CA_fat_free_crm.yml +142 -202
  240. data/config/locales/fr.yml +170 -125
  241. data/config/locales/fr_fat_free_crm.yml +199 -302
  242. data/config/locales/it.yml +158 -122
  243. data/config/locales/it_fat_free_crm.yml +105 -168
  244. data/config/locales/ja.yml +162 -131
  245. data/config/locales/ja_fat_free_crm.yml +118 -188
  246. data/config/locales/pl.yml +168 -132
  247. data/config/locales/pl_fat_free_crm.yml +115 -186
  248. data/config/locales/pt-BR.yml +160 -127
  249. data/config/locales/pt-BR_fat_free_crm.yml +125 -182
  250. data/config/locales/ru.yml +256 -233
  251. data/config/locales/ru_fat_free_crm.yml +136 -193
  252. data/config/locales/sv-SE.yml +164 -181
  253. data/config/locales/sv-SE_fat_free_crm.yml +129 -193
  254. data/config/locales/th_fat_free_crm.yml +114 -194
  255. data/config/locales/zh-CN.yml +176 -149
  256. data/config/locales/zh-CN_fat_free_crm.yml +78 -167
  257. data/config/routes.rb +1 -1
  258. data/config/settings.default.yml +74 -23
  259. data/custom_plan.rb +11 -0
  260. data/db/migrate/20131207033244_add_user_id_to_lists.rb +6 -0
  261. data/db/schema.rb +4 -1
  262. data/fat_free_crm.gemspec +3 -3
  263. data/lib/fat_free_crm.rb +1 -11
  264. data/lib/fat_free_crm/export_csv.rb +3 -3
  265. data/lib/fat_free_crm/fields.rb +10 -0
  266. data/lib/fat_free_crm/gem_dependencies.rb +1 -2
  267. data/lib/fat_free_crm/i18n.rb +9 -5
  268. data/lib/fat_free_crm/version.rb +2 -2
  269. data/lib/fat_free_crm/view_factory.rb +8 -5
  270. data/lib/tasks/ffcrm/config.rake +9 -12
  271. data/lib/tasks/ffcrm/missing_translations.rake +2 -1
  272. data/spec/controllers/admin/users_controller_spec.rb +6 -4
  273. data/spec/controllers/applications_controller_spec.rb +4 -4
  274. data/spec/controllers/authentications_controller_spec.rb +15 -15
  275. data/spec/controllers/comments_controller_spec.rb +9 -87
  276. data/spec/controllers/emails_controller_spec.rb +1 -1
  277. data/spec/controllers/entities/accounts_controller_spec.rb +7 -7
  278. data/spec/controllers/entities/campaigns_controller_spec.rb +5 -5
  279. data/spec/controllers/entities/contacts_controller_spec.rb +7 -7
  280. data/spec/controllers/entities/leads_controller_spec.rb +14 -14
  281. data/spec/controllers/entities/opportunities_controller_spec.rb +8 -8
  282. data/spec/controllers/home_controller_spec.rb +6 -6
  283. data/spec/controllers/tasks_controller_spec.rb +7 -7
  284. data/spec/controllers/users_controller_spec.rb +22 -50
  285. data/spec/features/support/selector_helpers.rb +1 -6
  286. data/spec/features/tasks_spec.rb +2 -2
  287. data/spec/helpers/application_helper_spec.rb +15 -15
  288. data/spec/lib/fields_spec.rb +29 -29
  289. data/spec/lib/mail_processor/base_spec.rb +7 -7
  290. data/spec/lib/mail_processor/dropbox_spec.rb +3 -3
  291. data/spec/lib/view_factory_spec.rb +14 -14
  292. data/spec/models/entities/opportunity_spec.rb +1 -1
  293. data/spec/models/fields/custom_field_date_pair_spec.rb +14 -14
  294. data/spec/models/fields/custom_field_pair_spec.rb +13 -13
  295. data/spec/models/fields/custom_field_spec.rb +5 -5
  296. data/spec/models/fields/field_spec.rb +2 -2
  297. data/spec/models/observers/entity_observer_spec.rb +2 -2
  298. data/spec/models/users/user_spec.rb +7 -7
  299. data/spec/routing/comments_routing_spec.rb +0 -9
  300. data/spec/shared/controllers.rb +75 -77
  301. data/spec/shared/models.rb +1 -1
  302. data/spec/spec_helper.rb +1 -2
  303. data/spec/support/auth_macros.rb +3 -3
  304. data/spec/support/mail_processor_mocks.rb +13 -13
  305. data/spec/views/accounts/_edit.haml_spec.rb +1 -1
  306. data/spec/views/accounts/{create.rjs_spec.rb → create.js.haml_spec.rb} +9 -14
  307. data/spec/views/accounts/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +6 -8
  308. data/spec/views/accounts/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +10 -18
  309. data/spec/views/accounts/{index.rjs_spec.rb → index.js.haml_spec.rb} +7 -11
  310. data/spec/views/accounts/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -8
  311. data/spec/views/accounts/show.haml_spec.rb +1 -1
  312. data/spec/views/accounts/{update.rjs_spec.rb → update.js.haml_spec.rb} +16 -25
  313. data/spec/views/admin/field_groups/create.js.haml_spec.rb +31 -0
  314. data/spec/views/admin/field_groups/destroy.js.haml_spec.rb +31 -0
  315. data/spec/views/admin/field_groups/edit.js.haml_spec.rb +24 -0
  316. data/spec/views/admin/field_groups/new.js.haml_spec.rb +25 -0
  317. data/spec/views/admin/field_groups/update.js.haml_spec.rb +30 -0
  318. data/spec/views/admin/users/_create.haml_spec.rb +1 -1
  319. data/spec/views/admin/users/{create.rjs_spec.rb → create.js.haml_spec.rb} +6 -9
  320. data/spec/views/admin/users/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +6 -7
  321. data/spec/views/admin/users/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +6 -12
  322. data/spec/views/admin/users/index.haml_spec.rb +0 -0
  323. data/spec/views/admin/users/{index.rjs_spec.rb → index.js.haml_spec.rb} +3 -5
  324. data/spec/views/admin/users/{new.rjs_spec.rb → new.js.haml_spec.rb} +4 -6
  325. data/spec/views/admin/users/{reactivate.rjs_spec.rb → reactivate.js.haml_spec.rb} +2 -4
  326. data/spec/views/admin/users/show.haml_spec.rb +0 -0
  327. data/spec/views/admin/users/{suspend.rjs_spec.rb → suspend.js.haml_spec.rb} +2 -4
  328. data/spec/views/admin/users/{update.rjs_spec.rb → update.js.haml_spec.rb} +6 -10
  329. data/spec/views/campaigns/{create.rjs_spec.rb → create.js.haml_spec.rb} +9 -14
  330. data/spec/views/campaigns/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +6 -7
  331. data/spec/views/campaigns/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +11 -19
  332. data/spec/views/campaigns/{index.rjs_spec.rb → index.js.haml_spec.rb} +5 -9
  333. data/spec/views/campaigns/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -8
  334. data/spec/views/campaigns/{update.rjs_spec.rb → update.js.haml_spec.rb} +14 -21
  335. data/spec/views/comments/{new.rjs_spec.rb → edit.js.haml_spec.rb} +12 -9
  336. data/spec/views/contacts/{create.rjs_spec.rb → create.js.haml_spec.rb} +9 -16
  337. data/spec/views/contacts/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +6 -8
  338. data/spec/views/contacts/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +12 -19
  339. data/spec/views/contacts/index.haml_spec.rb +1 -1
  340. data/spec/views/contacts/{index.rjs_spec.rb → index.js.html_spec.rb} +7 -11
  341. data/spec/views/contacts/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -7
  342. data/spec/views/contacts/{update.rjs_spec.rb → update.js.haml_spec.rb} +20 -35
  343. data/spec/views/home/{index.rjs_spec.rb → index.js.haml_spec.rb} +2 -4
  344. data/spec/views/home/{options.rjs_spec.rb → options.js.haml_spec.rb} +7 -12
  345. data/spec/views/leads/{convert.rjs_spec.rb → convert.js.haml_spec.rb} +12 -20
  346. data/spec/views/leads/{create.rjs_spec.rb → create.js.haml_spec.rb} +13 -19
  347. data/spec/views/leads/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +9 -12
  348. data/spec/views/leads/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +12 -20
  349. data/spec/views/leads/{index.rjs_spec.rb → index.js.haml_spec.rb} +5 -9
  350. data/spec/views/leads/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -8
  351. data/spec/views/leads/{promote.rjs_spec.rb → promote.js.haml_spec.rb} +28 -43
  352. data/spec/views/leads/{reject.rjs_spec.rb → reject.js.haml_spec.rb} +10 -17
  353. data/spec/views/leads/{update.rjs_spec.rb → update.js.haml_spec.rb} +25 -38
  354. data/spec/views/opportunities/{create.rjs_spec.rb → create.js.haml_spec.rb} +16 -26
  355. data/spec/views/opportunities/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +13 -16
  356. data/spec/views/opportunities/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +10 -18
  357. data/spec/views/opportunities/{index.rjs_spec.rb → index.js.haml_spec.rb} +7 -12
  358. data/spec/views/opportunities/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -8
  359. data/spec/views/opportunities/{update.rjs_spec.rb → update.js.haml_spec.rb} +29 -46
  360. data/spec/views/tasks/_edit.haml_spec.rb +1 -1
  361. data/spec/views/tasks/{complete.rjs_spec.rb → complete.js.haml_spec.rb} +9 -14
  362. data/spec/views/tasks/{create.rjs_spec.rb → create.js.haml_spec.rb} +25 -33
  363. data/spec/views/tasks/{destroy.rjs_spec.rb → destroy.js.haml_spec.rb} +9 -11
  364. data/spec/views/tasks/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +9 -14
  365. data/spec/views/tasks/index.haml_spec.rb +1 -2
  366. data/spec/views/tasks/{new.rjs_spec.rb → new.js.haml_spec.rb} +6 -8
  367. data/spec/views/tasks/{update.rjs_spec.rb → update.js.haml_spec.rb} +28 -41
  368. data/spec/views/users/{avatar.rjs_spec.rb → avatar.js.haml_spec.rb} +7 -9
  369. data/spec/views/users/{change_password.rjs_spec.rb → change_password.js.haml_spec.rb} +10 -12
  370. data/spec/views/users/{edit.rjs_spec.rb → edit.js.haml_spec.rb} +8 -10
  371. data/spec/views/users/{password.rjs_spec.rb → password.js.haml_spec.rb} +9 -11
  372. data/spec/views/users/{update.rjs_spec.rb → update.js.haml_spec.rb} +7 -15
  373. data/spec/views/users/{upload_avatar.rjs_spec.rb → upload_avatar.js.haml_spec.rb} +8 -10
  374. data/vendor/assets/javascripts/ajax-chosen-jquery.js +2 -0
  375. data/vendor/assets/javascripts/ajax-chosen-prototype.js +2 -0
  376. data/vendor/assets/javascripts/ajax-chosen.jquery.coffee +81 -0
  377. data/vendor/assets/javascripts/ajax-chosen.proto.coffee +98 -0
  378. data/vendor/assets/javascripts/jquery_timeago/index.js +17 -0
  379. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.cz.js +18 -0
  380. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.de.js +18 -0
  381. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.en-GB.js +20 -0
  382. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.en-US.js +20 -0
  383. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.es.js +18 -0
  384. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.fr-CA.js +17 -0
  385. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.fr.js +17 -0
  386. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.it.js +16 -0
  387. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.ja.js +19 -0
  388. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.js +194 -0
  389. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pl.js +31 -0
  390. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.pt-BR.js +18 -0
  391. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.ru.js +34 -0
  392. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.sv-SE.js +18 -0
  393. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.th.js +20 -0
  394. data/vendor/assets/javascripts/jquery_timeago/jquery.timeago.zh-CN.js +20 -0
  395. data/zeus.json +2 -1
  396. metadata +240 -245
  397. data/app/assets/images/delete.png +0 -0
  398. data/app/assets/images/iconset_attribution.png +0 -0
  399. data/app/views/accounts/create.js.rjs +0 -14
  400. data/app/views/accounts/destroy.js.rjs +0 -3
  401. data/app/views/accounts/edit.js.rjs +0 -33
  402. data/app/views/accounts/index.js.rjs +0 -8
  403. data/app/views/accounts/new.js.rjs +0 -9
  404. data/app/views/accounts/show.js.erb +0 -2
  405. data/app/views/accounts/update.js.rjs +0 -17
  406. data/app/views/admin/field_groups/confirm.js.rjs +0 -6
  407. data/app/views/admin/field_groups/create.js.rjs +0 -20
  408. data/app/views/admin/field_groups/destroy.js.rjs +0 -11
  409. data/app/views/admin/field_groups/edit.js.rjs +0 -14
  410. data/app/views/admin/field_groups/new.js.rjs +0 -9
  411. data/app/views/admin/field_groups/update.js.rjs +0 -9
  412. data/app/views/admin/fields/create.js.erb +0 -19
  413. data/app/views/admin/fields/destroy.js.erb +0 -9
  414. data/app/views/admin/fields/edit.js.erb +0 -1
  415. data/app/views/admin/fields/update.js.erb +0 -13
  416. data/app/views/admin/groups/create.js.rjs +0 -11
  417. data/app/views/admin/groups/destroy.js.rjs +0 -11
  418. data/app/views/admin/groups/edit.js.rjs +0 -21
  419. data/app/views/admin/groups/index.js.rjs +0 -2
  420. data/app/views/admin/groups/new.js.rjs +0 -9
  421. data/app/views/admin/groups/update.js.rjs +0 -10
  422. data/app/views/admin/tags/confirm.js.rjs +0 -6
  423. data/app/views/admin/tags/create.js.rjs +0 -12
  424. data/app/views/admin/tags/destroy.js.rjs +0 -11
  425. data/app/views/admin/tags/edit.js.rjs +0 -21
  426. data/app/views/admin/tags/new.js.rjs +0 -8
  427. data/app/views/admin/tags/update.js.rjs +0 -10
  428. data/app/views/admin/users/confirm.js.rjs +0 -6
  429. data/app/views/admin/users/create.js.rjs +0 -11
  430. data/app/views/admin/users/destroy.js.rjs +0 -11
  431. data/app/views/admin/users/edit.js.rjs +0 -21
  432. data/app/views/admin/users/index.js.rjs +0 -3
  433. data/app/views/admin/users/new.js.rjs +0 -8
  434. data/app/views/admin/users/reactivate.js.rjs +0 -3
  435. data/app/views/admin/users/suspend.js.rjs +0 -3
  436. data/app/views/admin/users/update.js.rjs +0 -10
  437. data/app/views/campaigns/create.js.rjs +0 -18
  438. data/app/views/campaigns/destroy.js.rjs +0 -3
  439. data/app/views/campaigns/edit.js.rjs +0 -34
  440. data/app/views/campaigns/index.js.rjs +0 -8
  441. data/app/views/campaigns/new.js.rjs +0 -9
  442. data/app/views/campaigns/show.js.erb +0 -2
  443. data/app/views/campaigns/update.js.rjs +0 -21
  444. data/app/views/comments/create.js.rjs +0 -11
  445. data/app/views/comments/destroy.js.rjs +0 -6
  446. data/app/views/comments/edit.js.rjs +0 -11
  447. data/app/views/comments/new.js.rjs +0 -14
  448. data/app/views/comments/update.js.rjs +0 -11
  449. data/app/views/contacts/create.js.rjs +0 -19
  450. data/app/views/contacts/destroy.js.rjs +0 -7
  451. data/app/views/contacts/edit.js.rjs +0 -36
  452. data/app/views/contacts/index.js.rjs +0 -8
  453. data/app/views/contacts/new.js.rjs +0 -11
  454. data/app/views/contacts/show.js.erb +0 -2
  455. data/app/views/contacts/update.js.rjs +0 -22
  456. data/app/views/emails/destroy.js.rjs +0 -6
  457. data/app/views/entities/attach.js.rjs +0 -24
  458. data/app/views/entities/contacts.js.rjs +0 -3
  459. data/app/views/entities/discard.js.rjs +0 -7
  460. data/app/views/entities/leads.js.rjs +0 -3
  461. data/app/views/entities/opportunities.js.rjs +0 -3
  462. data/app/views/entities/subscription_update.js.rjs +0 -4
  463. data/app/views/entities/versions.js.erb +0 -3
  464. data/app/views/fields/group.js.rjs +0 -7
  465. data/app/views/home/index.js.rjs +0 -7
  466. data/app/views/home/options.js.rjs +0 -8
  467. data/app/views/leads/convert.js.rjs +0 -37
  468. data/app/views/leads/create.js.rjs +0 -19
  469. data/app/views/leads/destroy.js.rjs +0 -7
  470. data/app/views/leads/edit.js.rjs +0 -36
  471. data/app/views/leads/index.js.rjs +0 -8
  472. data/app/views/leads/new.js.rjs +0 -9
  473. data/app/views/leads/promote.js.rjs +0 -27
  474. data/app/views/leads/reject.js.rjs +0 -10
  475. data/app/views/leads/show.js.erb +0 -2
  476. data/app/views/leads/update.js.rjs +0 -27
  477. data/app/views/lists/create.js.rjs +0 -9
  478. data/app/views/lists/destroy.js.rjs +0 -1
  479. data/app/views/opportunities/contacts.js.rjs +0 -3
  480. data/app/views/opportunities/create.js.rjs +0 -29
  481. data/app/views/opportunities/destroy.js.rjs +0 -11
  482. data/app/views/opportunities/edit.js.rjs +0 -36
  483. data/app/views/opportunities/index.js.rjs +0 -8
  484. data/app/views/opportunities/new.js.rjs +0 -12
  485. data/app/views/opportunities/show.js.erb +0 -2
  486. data/app/views/opportunities/update.js.rjs +0 -26
  487. data/app/views/tasks/complete.js.rjs +0 -17
  488. data/app/views/tasks/create.js.rjs +0 -41
  489. data/app/views/tasks/destroy.js.rjs +0 -7
  490. data/app/views/tasks/discard.rjs +0 -1
  491. data/app/views/tasks/edit.js.rjs +0 -23
  492. data/app/views/tasks/filter.js.rjs +0 -1
  493. data/app/views/tasks/new.js.rjs +0 -9
  494. data/app/views/tasks/update.js.rjs +0 -21
  495. data/app/views/users/avatar.js.rjs +0 -10
  496. data/app/views/users/change_password.js.rjs +0 -15
  497. data/app/views/users/edit.js.rjs +0 -10
  498. data/app/views/users/password.js.rjs +0 -11
  499. data/app/views/users/update.js.rjs +0 -10
  500. data/app/views/users/upload_avatar.js.rjs +0 -8
  501. data/lib/fat_free_crm/secret_token_generator.rb +0 -65
  502. data/spec/lib/secret_token_generator_spec.rb +0 -79
  503. data/spec/models/users/abilities/user_ability_spec.rb +0 -58
  504. data/spec/support/rjs_support.rb +0 -14
  505. data/vendor/assets/images/brief.png +0 -0
  506. data/vendor/assets/images/full.png +0 -0
  507. data/vendor/assets/images/long.png +0 -0
  508. data/vendor/assets/images/tab_icons/accounts.png +0 -0
  509. data/vendor/assets/images/tab_icons/accounts_active.png +0 -0
  510. data/vendor/assets/images/tab_icons/campaigns.png +0 -0
  511. data/vendor/assets/images/tab_icons/campaigns_active.png +0 -0
  512. data/vendor/assets/images/tab_icons/contacts.png +0 -0
  513. data/vendor/assets/images/tab_icons/contacts_active.png +0 -0
  514. data/vendor/assets/images/tab_icons/dashboard.png +0 -0
  515. data/vendor/assets/images/tab_icons/dashboard_active.png +0 -0
  516. data/vendor/assets/images/tab_icons/leads.png +0 -0
  517. data/vendor/assets/images/tab_icons/leads_active.png +0 -0
  518. data/vendor/assets/images/tab_icons/opportunities.png +0 -0
  519. data/vendor/assets/images/tab_icons/opportunities_active.png +0 -0
  520. data/vendor/assets/images/tab_icons/tasks.png +0 -0
  521. data/vendor/assets/images/tab_icons/tasks_active.png +0 -0
@@ -49,6 +49,7 @@
49
49
  class CustomField < Field
50
50
  after_validation :update_column, :on => :update
51
51
  before_create :add_column
52
+ after_create :add_ransack_translation
52
53
 
53
54
  SAFE_DB_TRANSITIONS = {
54
55
  :any => [['date', 'time', 'timestamp'], ['integer', 'float']],
@@ -129,6 +130,15 @@ class CustomField < Field
129
130
  klass.serialize_custom_fields!
130
131
  end
131
132
 
133
+ # Adds custom field translation for Ransack
134
+ def add_ransack_translation
135
+ I18n.backend.store_translations(Setting.locale.to_sym, {
136
+ ransack: {attributes: {klass.model_name.singular => {name => label}}}
137
+ })
138
+ # Reset Ransack cache
139
+ Ransack::Helpers::FormBuilder.cached_searchable_attributes_for_base = {}
140
+ end
141
+
132
142
  # Change database column type only if safe to do so
133
143
  # Note: columns will never be renamed or destroyed
134
144
  #------------------------------------------------------------------------------
@@ -33,9 +33,9 @@ class Field < ActiveRecord::Base
33
33
 
34
34
  belongs_to :field_group
35
35
 
36
- scope :core_fields, where(:type => 'CoreField')
37
- scope :custom_fields, where("type != 'CoreField'")
38
- scope :without_pairs, where(:pair_id => nil)
36
+ scope :core_fields, -> { where(:type => 'CoreField') }
37
+ scope :custom_fields, -> { where("type != 'CoreField'") }
38
+ scope :without_pairs, -> { where(:pair_id => nil) }
39
39
 
40
40
  delegate :klass, :klass_name, :klass_name=, :to => :field_group
41
41
 
@@ -54,7 +54,7 @@ class FieldGroup < ActiveRecord::Base
54
54
  # When deleted, transfer fields to default field group
55
55
  def move_fields_to_default_field_group
56
56
  default_group = FieldGroup.find_by_name_and_klass_name("custom_fields", klass_name)
57
- default_group.fields << fields
57
+ default_group.fields << fields if default_group
58
58
  self.reload
59
59
  end
60
60
 
@@ -5,6 +5,7 @@
5
5
  #------------------------------------------------------------------------------
6
6
  class List < ActiveRecord::Base
7
7
  validates_presence_of :name
8
+ belongs_to :user
8
9
 
9
10
  # Parses the controller from the url
10
11
  def controller
@@ -28,9 +28,9 @@ class Address < ActiveRecord::Base
28
28
 
29
29
  has_paper_trail :meta => { :related => :addressable }
30
30
 
31
- scope :business, :conditions => "address_type='Business'"
32
- scope :billing, :conditions => "address_type='Billing'"
33
- scope :shipping, :conditions => "address_type='Shipping'"
31
+ scope :business, -> { where("address_type='Business'") }
32
+ scope :billing, -> { where("address_type='Billing'") }
33
+ scope :shipping, -> { where("address_type='Shipping'") }
34
34
 
35
35
  # Checks if the address is blank for both single and compound addresses.
36
36
  #----------------------------------------------------------------------------
@@ -44,12 +44,10 @@ class Comment < ActiveRecord::Base
44
44
 
45
45
  # Notify subscribed users when a comment is added, unless user created this comment
46
46
  def notify_subscribers
47
+ return unless Rails.application.config.action_mailer.smtp_settings.present?
47
48
  commentable.subscribed_users.reject{|user_id| user_id == user.id}.each do |subscriber_id|
48
49
  if subscriber = User.find_by_id(subscriber_id)
49
- # Only send email if SMTP settings are configured
50
- if Rails.application.config.action_mailer.smtp_settings.present?
51
- SubscriptionMailer.comment_notification(subscriber, self).deliver
52
- end
50
+ SubscriptionMailer.comment_notification(subscriber, self).deliver
53
51
  end
54
52
  end
55
53
  end
@@ -37,62 +37,67 @@ class Task < ActiveRecord::Base
37
37
 
38
38
  # Tasks created by the user for herself, or assigned to her by others. That's
39
39
  # what gets shown on Tasks/Pending and Tasks/Completed pages.
40
- scope :my, lambda { |*args|
40
+ scope :my, ->(*args) {
41
41
  options = args[0] || {}
42
- user_option = options[:user] || User.current_user
42
+ user_option = (options.is_a?(Hash) ? options[:user] : options) || User.current_user
43
43
  includes(:assignee).
44
44
  where('(user_id = ? AND assigned_to IS NULL) OR assigned_to = ?', user_option, user_option).
45
45
  order(options[:order] || 'name ASC').
46
46
  limit(options[:limit]) # nil selects all records
47
47
  }
48
48
 
49
+ scope :created_by, ->(user) { where(:user_id => user.id) }
50
+ scope :assigned_to, ->(user) { where(:assigned_to => user.id) }
51
+
49
52
  # Tasks assigned by the user to others. That's what we see on Tasks/Assigned.
50
- scope :assigned_by, lambda { |user|
53
+ scope :assigned_by, ->(user) {
51
54
  includes(:assignee).
52
55
  where('user_id = ? AND assigned_to IS NOT NULL AND assigned_to != ?', user.id, user.id)
53
56
  }
54
57
 
55
58
  # Tasks created by the user or assigned to the user, i.e. the union of the two
56
59
  # scopes above. That's the tasks the user is allowed to see and track.
57
- scope :tracked_by, lambda { |user|
60
+ scope :tracked_by, ->(user) {
58
61
  includes(:assignee).
59
62
  where('user_id = ? OR assigned_to = ?', user.id, user.id)
60
63
  }
61
64
 
62
- scope :visible_on_dashboard, lambda { |user|
65
+ scope :visible_on_dashboard, ->(user) {
63
66
  # Show opportunities which either belong to the user and are unassigned, or are assigned to the user
64
67
  where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', :user_id => user.id).where('completed_at IS NULL')
65
68
  }
66
69
 
67
- scope :by_due_at, order({
68
- "MySQL" => "due_at NOT NULL, due_at ASC",
69
- "PostgreSQL" => "due_at ASC NULLS FIRST"
70
- }[ActiveRecord::Base.connection.adapter_name] || :due_at)
70
+ scope :by_due_at, -> {
71
+ order({
72
+ "MySQL" => "due_at NOT NULL, due_at ASC",
73
+ "PostgreSQL" => "due_at ASC NULLS FIRST"
74
+ }[ActiveRecord::Base.connection.adapter_name] || :due_at)
75
+ }
71
76
 
72
77
 
73
78
  # Status based scopes to be combined with the due date and completion time.
74
- scope :pending, where('completed_at IS NULL').order('tasks.due_at, tasks.id')
75
- scope :assigned, where('completed_at IS NULL AND assigned_to IS NOT NULL').order('tasks.due_at, tasks.id')
76
- scope :completed, where('completed_at IS NOT NULL').order('tasks.completed_at DESC')
79
+ scope :pending, -> { where('completed_at IS NULL').order('tasks.due_at, tasks.id') }
80
+ scope :assigned, -> { where('completed_at IS NULL AND assigned_to IS NOT NULL').order('tasks.due_at, tasks.id') }
81
+ scope :completed, -> { where('completed_at IS NOT NULL').order('tasks.completed_at DESC') }
77
82
 
78
83
  # Due date scopes.
79
- scope :due_asap, where("due_at IS NULL AND bucket = 'due_asap'").order('tasks.id DESC')
80
- scope :overdue, where('due_at IS NOT NULL AND due_at < ?', Time.zone.now.midnight.utc).order('tasks.id DESC')
81
- scope :due_today, where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc).order('tasks.id DESC')
82
- scope :due_tomorrow, where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc, Time.zone.now.midnight.tomorrow.utc + 1.day).order('tasks.id DESC')
83
- scope :due_this_week, where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc + 1.day, Time.zone.now.next_week.utc).order('tasks.id DESC')
84
- scope :due_next_week, where('due_at >= ? AND due_at < ?', Time.zone.now.next_week.utc, Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC')
85
- scope :due_later, where("(due_at IS NULL AND bucket = 'due_later') OR due_at >= ?", Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC')
84
+ scope :due_asap, -> { where("due_at IS NULL AND bucket = 'due_asap'").order('tasks.id DESC') }
85
+ scope :overdue, -> { where('due_at IS NOT NULL AND due_at < ?', Time.zone.now.midnight.utc).order('tasks.id DESC') }
86
+ scope :due_today, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc).order('tasks.id DESC') }
87
+ scope :due_tomorrow, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc, Time.zone.now.midnight.tomorrow.utc + 1.day).order('tasks.id DESC') }
88
+ scope :due_this_week, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.midnight.tomorrow.utc + 1.day, Time.zone.now.next_week.utc).order('tasks.id DESC') }
89
+ scope :due_next_week, -> { where('due_at >= ? AND due_at < ?', Time.zone.now.next_week.utc, Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
90
+ scope :due_later, -> { where("(due_at IS NULL AND bucket = 'due_later') OR due_at >= ?", Time.zone.now.next_week.end_of_week.utc + 1.day).order('tasks.id DESC') }
86
91
 
87
92
  # Completion time scopes.
88
- scope :completed_today, where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc)
89
- scope :completed_yesterday, where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.yesterday.utc, Time.zone.now.midnight.utc)
90
- scope :completed_this_week, where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc , Time.zone.now.midnight.yesterday.utc)
91
- scope :completed_last_week, where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc - 7.days, Time.zone.now.beginning_of_week.utc)
92
- scope :completed_this_month, where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_month.utc, Time.zone.now.beginning_of_week.utc - 7.days)
93
- scope :completed_last_month, where('completed_at >= ? AND completed_at < ?', (Time.zone.now.beginning_of_month.utc - 1.day).beginning_of_month.utc, Time.zone.now.beginning_of_month.utc)
94
-
95
- scope :text_search, lambda { |query|
93
+ scope :completed_today, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.utc, Time.zone.now.midnight.tomorrow.utc) }
94
+ scope :completed_yesterday, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.midnight.yesterday.utc, Time.zone.now.midnight.utc) }
95
+ scope :completed_this_week, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc , Time.zone.now.midnight.yesterday.utc) }
96
+ scope :completed_last_week, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_week.utc - 7.days, Time.zone.now.beginning_of_week.utc) }
97
+ scope :completed_this_month, -> { where('completed_at >= ? AND completed_at < ?', Time.zone.now.beginning_of_month.utc, Time.zone.now.beginning_of_week.utc - 7.days) }
98
+ scope :completed_last_month, -> { where('completed_at >= ? AND completed_at < ?', (Time.zone.now.beginning_of_month.utc - 1.day).beginning_of_month.utc, Time.zone.now.beginning_of_month.utc) }
99
+
100
+ scope :text_search, ->(query) {
96
101
  query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
97
102
  where('upper(name) LIKE upper(?)', "%#{query}%")
98
103
  }
@@ -101,16 +101,10 @@ class Setting < ActiveRecord::Base
101
101
 
102
102
  # Loads settings from YAML files
103
103
  def load_settings_from_yaml(file)
104
- begin
105
- YAML::ENGINE.yamler = 'syck' # remove this when files are converted to Psych
106
- settings = YAML.load_file(file)
107
- # Merge settings into current settings hash (recursively)
108
- @@yaml_settings.deep_merge!(settings)
109
- rescue Exception => ex
110
- puts "Settings couldn't be loaded from #{file}: #{ex.message}"
111
- end
112
- yaml_settings
104
+ settings = YAML.load_file(file)
105
+ @@yaml_settings.deep_merge!(settings)
113
106
  end
107
+
114
108
  end
115
109
 
116
110
  ActiveSupport.run_load_hooks(:fat_free_crm_setting, self)
@@ -9,22 +9,11 @@ class Ability
9
9
  include CanCan::Ability
10
10
 
11
11
  def initialize(user)
12
-
13
- # handle signup
14
- can(:create, User) if User.can_signup?
15
-
16
12
  if user.present?
17
13
  entities = [Account, Campaign, Contact, Lead, Opportunity]
18
14
 
19
- # User
20
- can :manage, User, id: user.id # can do any action on themselves
21
-
22
- # Tasks
23
- can :create, Task
24
- can :manage, Task, user: user.id
25
- can :manage, Task, assigned_to: user.id
26
-
27
- # Entities
15
+ can :create, :all
16
+ can :read, [User] # for search autocomplete
28
17
  can :manage, entities, :access => 'Public'
29
18
  can :manage, entities + [Task], :user_id => user.id
30
19
  can :manage, entities + [Task], :assigned_to => user.id
@@ -56,27 +56,28 @@ class User < ActiveRecord::Base
56
56
  has_many :assigned_opportunities, :class_name => 'Opportunity', :foreign_key => 'assigned_to'
57
57
  has_many :permissions, :dependent => :destroy
58
58
  has_many :preferences, :dependent => :destroy
59
+ has_many :lists
59
60
  has_and_belongs_to_many :groups
60
61
 
61
62
  has_paper_trail :ignore => [:last_request_at, :perishable_token]
62
63
 
63
64
  # For some reason this does not play nice with has_paper_trail when set as default scope
64
- scope :by_id, order('id DESC')
65
- scope :except, lambda { |user| where('id != ?', user.id).by_name }
66
- scope :by_name, order('first_name, last_name, email')
65
+ scope :by_id, -> { order('id DESC') }
66
+ scope :except, ->(user) { where('id != ?', user.id).by_name }
67
+ scope :by_name, -> { order('first_name, last_name, email') }
67
68
 
68
- scope :text_search, lambda { |query|
69
+ scope :text_search, ->(query) {
69
70
  query = query.gsub(/[^\w\s\-\.'\p{L}]/u, '').strip
70
71
  where('upper(username) LIKE upper(:s) OR upper(first_name) LIKE upper(:s) OR upper(last_name) LIKE upper(:s)', :s => "%#{query}%")
71
72
  }
72
73
 
73
- scope :my, lambda {
74
- accessible_by(User.current_ability)
75
- }
74
+ scope :my, -> { accessible_by(User.current_ability) }
76
75
 
77
- scope :have_assigned_opportunities, joins("INNER JOIN opportunities ON users.id = opportunities.assigned_to").
78
- where("opportunities.stage <> 'lost' AND opportunities.stage <> 'won'").
79
- select('DISTINCT(users.id), users.*')
76
+ scope :have_assigned_opportunities, -> {
77
+ joins("INNER JOIN opportunities ON users.id = opportunities.assigned_to")
78
+ .where("opportunities.stage <> 'lost' AND opportunities.stage <> 'won'")
79
+ .select('DISTINCT(users.id), users.*')
80
+ }
80
81
 
81
82
  acts_as_authentic do |c|
82
83
  c.session_class = Authentication
@@ -171,7 +172,7 @@ class User < ActiveRecord::Base
171
172
  # Prevent deleting a user unless she has no artifacts left.
172
173
  #----------------------------------------------------------------------------
173
174
  def check_if_has_related_assets
174
- artifacts = %w(Account Campaign Lead Contact Opportunity Comment).inject(0) do |sum, asset|
175
+ artifacts = %w(Account Campaign Lead Contact Opportunity Comment Task).inject(0) do |sum, asset|
175
176
  klass = asset.constantize
176
177
  sum += klass.assigned_to(self).count if asset != "Comment"
177
178
  sum += klass.created_by(self).count
@@ -187,10 +188,6 @@ class User < ActiveRecord::Base
187
188
  Ability.new(User.current_user)
188
189
  end
189
190
 
190
- def can_signup?
191
- [ :allowed, :needs_approval ].include? Setting.user_signup
192
- end
193
-
194
191
  end
195
192
 
196
193
  ActiveSupport.run_load_hooks(:fat_free_crm_user, self)
@@ -1,5 +1,5 @@
1
1
  .remote
2
- = simple_form_for(@account, :html => one_submit_only(:account), :remote => true) do |f|
2
+ = simple_form_for(@account, :html => one_submit_only, :remote => true) do |f|
3
3
  = link_to_close edit_account_path(@account)
4
4
  = f.hidden_field :user_id
5
5
 
@@ -21,11 +21,11 @@
21
21
  &ndash;
22
22
  %tt
23
23
  = account.location << ", " unless account.location.blank?
24
- - user_name = account.user_id == current_user.id ? t(:me) : account.user.try(:full_name)
24
+ - user_name = account.user.try(:full_name)
25
25
  - if user_name
26
- = t(:added_by, :time_ago => time_ago_in_words(account.created_at), :user => user_name) << " | "
26
+ = t(:added_by, :time_ago => timeago(account.created_at), :user => h(user_name)).html_safe << " | "
27
27
  - else
28
- = t(:added_ago, :value => time_ago_in_words(account.created_at)) << " | "
28
+ = t(:added_ago, :value => timeago(account.created_at)).html_safe << " | "
29
29
  = t('pluralize.contact', account.contacts.count) << " | "
30
30
  = t('pluralize.opportunity', account.opportunities.count)
31
31
 
@@ -21,11 +21,11 @@
21
21
  &ndash;
22
22
  %tt
23
23
  = account.location << ", " unless account.location.blank?
24
- - user_name = account.user_id == current_user.id ? t(:me) : account.user.try(:full_name)
24
+ - user_name = account.user.try(:full_name)
25
25
  - if user_name
26
- = t(:added_by, :time_ago => time_ago_in_words(account.created_at), :user => user_name) << " | "
26
+ = t(:added_by, :time_ago => timeago(account.created_at), :user => h(user_name)).html_safe << " | "
27
27
  - else
28
- = t(:added_ago, :value => time_ago_in_words(account.created_at)) << " | "
28
+ = t(:added_ago, :value => timeago(account.created_at)).html_safe << " | "
29
29
  = t('pluralize.contact', account.contacts.count) << " | "
30
30
  = t('pluralize.opportunity', account.opportunities.count)
31
31
 
@@ -1,4 +1,4 @@
1
- = simple_form_for(@account, :html => one_submit_only(:account), :remote => true) do |f|
1
+ = simple_form_for(@account, :html => one_submit_only, :remote => true) do |f|
2
2
  = link_to_close new_account_path
3
3
  = f.hidden_field :user_id
4
4
 
@@ -0,0 +1,17 @@
1
+ - entity_name = controller.controller_name.singularize.underscore #account
2
+ - @entity = instance_variable_get("@#{entity_name}")
3
+ - create_id = "create_#{entity_name}" # create_account
4
+
5
+ - if @entity.valid?
6
+ jQuery('##{create_id}_arrow').html(crm.COLLAPSED);
7
+ jQuery('##{create_id}_title').html('#{ j t(entity_name.pluralize) }');
8
+ jQuery('##{create_id}').slideUp(250);
9
+ jQuery('##{entity_name.pluralize}').prepend('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
10
+ jQuery('##{dom_id(@entity)}').effect("highlight", { duration:1500 });
11
+ = refresh_sidebar(:index, :filters)
12
+ jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
13
+ crm.flick('empty', 'remove');
14
+ - else
15
+ jQuery('##{create_id}').html('#{ j render(:partial => "new") }');
16
+ jQuery('##{create_id}').effect("shake", { duration:250, distance: 6 });
17
+ jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
@@ -0,0 +1,6 @@
1
+ - entity_name = controller.controller_name.singularize.underscore
2
+ - @entity = instance_variable_get("@#{entity_name}")
3
+
4
+ jQuery('##{dom_id(@entity)}').css('background-color', '#ffe4e1').slideUp(250);
5
+ = refresh_sidebar(:index, :filters)
6
+ jQuery('#paginate').replaceWith('#{ j render(:partial => "shared/paginate_with_per_page") }');
@@ -0,0 +1,32 @@
1
+ - entity_name = controller.controller_name.singularize.underscore #account
2
+ - @entity = instance_variable_get("@#{entity_name}")
3
+ - id = dom_id(@entity)
4
+
5
+ - if params[:cancel].true? # <--------------------- Hide [Edit]
6
+
7
+ - if called_from_landing_page?
8
+ crm.flip_form('edit_#{entity_name}');
9
+ crm.set_title('edit_#{entity_name}', '#{h @entity.name}');
10
+ - else # Called from index page...
11
+ jQuery('##{id}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @entity ]) }');
12
+
13
+ - else # <---------------------------------------- Show [Edit] form.
14
+
15
+ - if params[:cancel].blank? # Called from index page...
16
+ - if @previous # Hide open [Edit] form if any.
17
+ - if @previous.is_a?(@entity.class)
18
+ jQuery('##{dom_id(@previous)}').replaceWith('#{ j render(:partial => entity_name, :collection => [ @previous ]) }');
19
+ - else
20
+ crm.flick('#{entity_name}_#{@previous}', 'remove');
21
+ -# Disable onMouseOver for the list item.
22
+ crm.highlight_off('#{id}');
23
+ -# Hide [Create] form if any.
24
+ crm.hide_form('create_#{entity_name}');
25
+ -# Show [Edit] form.
26
+ jQuery('##{id}').html('#{ j render(:partial => "edit") }');
27
+
28
+ - elsif params[:cancel].false? # Called from title of the landing page...
29
+ jQuery('#edit_#{entity_name}').html('#{ j render(:partial => "edit") }');
30
+ crm.flip_form('edit_#{entity_name}');
31
+ crm.set_title('edit_#{entity_name}', "#{t :edit} #{h @entity.name}");
32
+ jQuery('#new_#{entity_name} input[type!=hidden]').first().focus();
@@ -0,0 +1,11 @@
1
+ - entities = controller.controller_name # accounts
2
+ - @entities = instance_variable_get("@#{entities}")
3
+
4
+ - if @entities.any?
5
+ jQuery('##{entities}').html('#{ j render(@entities) }');
6
+ - else
7
+ jQuery('##{entities}').html('#{ j render(:partial => "shared/empty") }');
8
+
9
+ jQuery('#paginate').html('#{ j render(:partial => "shared/paginate_with_per_page") }');
10
+ jQuery('#export').html('#{ j render(:partial => "shared/export") }');
11
+ jQuery('#search_results_count').html('#{ j render(:text => t('search_results_count', :count => @search_results_count)) }');
@@ -3,7 +3,8 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
3
3
  unless @accounts.empty?
4
4
  # Header.
5
5
  xml.Row do
6
- heads = [I18n.t('user'),
6
+ heads = [I18n.t('id'),
7
+ I18n.t('user'),
7
8
  I18n.t('assigned_to'),
8
9
  I18n.t('name'),
9
10
  I18n.t('email'),
@@ -24,12 +25,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
24
25
  I18n.t('zipcode'),
25
26
  I18n.t('country'),
26
27
  I18n.t('address')]
27
-
28
+
28
29
  # Append custom field labels to header
29
30
  Account.fields.each do |field|
30
31
  heads << field.label
31
32
  end
32
-
33
+
33
34
  heads.each do |head|
34
35
  xml.Cell do
35
36
  xml.Data head,
@@ -37,12 +38,13 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
37
38
  end
38
39
  end
39
40
  end
40
-
41
+
41
42
  # Account rows.
42
43
  @accounts.each do |account|
43
44
  xml.Row do
44
45
  address = account.billing_address
45
- data = [account.user.try(:name),
46
+ data = [account.id,
47
+ account.user.try(:name),
46
48
  account.assignee.try(:name),
47
49
  account.name,
48
50
  account.email,
@@ -63,12 +65,12 @@ xml.Worksheet 'ss:Name' => I18n.t(:tab_accounts) do
63
65
  address.try(:zipcode),
64
66
  address.try(:country),
65
67
  address.try(:full_address)]
66
-
68
+
67
69
  # Append custom field values.
68
70
  Account.fields.each do |field|
69
71
  data << account.send(field.name)
70
72
  end
71
-
73
+
72
74
  data.each do |value|
73
75
  xml.Cell do
74
76
  xml.Data value,