fat_free_crm 0.18.2 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +61 -160
  3. data/.travis.yml +27 -11
  4. data/CHANGELOG.md +40 -24
  5. data/CONTRIBUTORS.md +1 -0
  6. data/Dockerfile +45 -14
  7. data/Gemfile +16 -10
  8. data/Gemfile.lock +230 -222
  9. data/Procfile +1 -1
  10. data/README.md +2 -2
  11. data/Rakefile +1 -1
  12. data/app/assets/stylesheets/common.scss +1 -1
  13. data/app/controllers/admin/application_controller.rb +1 -1
  14. data/app/controllers/admin/field_groups_controller.rb +1 -3
  15. data/app/controllers/admin/tags_controller.rb +1 -3
  16. data/app/controllers/admin/users_controller.rb +5 -8
  17. data/app/controllers/application_controller.rb +11 -45
  18. data/app/controllers/comments_controller.rb +2 -5
  19. data/{config/initializers/authlogic.rb → app/controllers/confirmations_controller.rb} +4 -2
  20. data/app/controllers/emails_controller.rb +0 -2
  21. data/app/controllers/entities/accounts_controller.rb +1 -3
  22. data/app/controllers/entities/campaigns_controller.rb +1 -3
  23. data/app/controllers/entities/contacts_controller.rb +4 -24
  24. data/app/controllers/entities/leads_controller.rb +7 -10
  25. data/app/controllers/entities/opportunities_controller.rb +4 -14
  26. data/app/controllers/entities_controller.rb +21 -7
  27. data/app/controllers/home_controller.rb +2 -4
  28. data/app/controllers/passwords_controller.rb +3 -59
  29. data/{spec/features/support/maintain_sessions.rb → app/controllers/registrations_controller.rb} +12 -5
  30. data/{lib/development_tasks/gem.rake → app/controllers/sessions_controller.rb} +6 -6
  31. data/app/controllers/tasks_controller.rb +8 -17
  32. data/app/controllers/users_controller.rb +8 -29
  33. data/app/helpers/admin/users_helper.rb +1 -1
  34. data/app/helpers/application_helper.rb +27 -32
  35. data/app/helpers/campaigns_helper.rb +1 -1
  36. data/app/helpers/contacts_helper.rb +1 -3
  37. data/app/helpers/opportunities_helper.rb +4 -12
  38. data/app/helpers/tasks_helper.rb +1 -1
  39. data/app/helpers/users_helper.rb +1 -3
  40. data/{config/initializers/paper_trail.rb → app/mailers/devise_mailer.rb} +5 -1
  41. data/app/mailers/user_mailer.rb +0 -9
  42. data/app/models/entities/account.rb +10 -10
  43. data/app/models/entities/campaign.rb +4 -6
  44. data/app/models/entities/contact.rb +24 -12
  45. data/app/models/entities/lead.rb +7 -7
  46. data/app/models/entities/opportunity.rb +7 -9
  47. data/app/models/fields/custom_field.rb +1 -0
  48. data/app/models/fields/custom_field_date_pair.rb +2 -0
  49. data/app/models/fields/field.rb +1 -3
  50. data/app/models/list.rb +1 -1
  51. data/app/models/observers/entity_observer.rb +3 -7
  52. data/app/models/observers/lead_observer.rb +2 -4
  53. data/app/models/observers/opportunity_observer.rb +2 -4
  54. data/app/models/observers/task_observer.rb +1 -1
  55. data/app/models/polymorphic/email.rb +2 -2
  56. data/app/models/polymorphic/task.rb +13 -9
  57. data/app/models/polymorphic/version.rb +3 -2
  58. data/app/models/setting.rb +2 -0
  59. data/app/models/users/permission.rb +3 -3
  60. data/app/models/users/preference.rb +2 -1
  61. data/app/models/users/user.rb +67 -42
  62. data/app/views/accounts/_top_section.html.haml +1 -1
  63. data/app/views/accounts/edit.js.haml +1 -1
  64. data/app/views/accounts/update.js.haml +2 -2
  65. data/app/views/admin/users/_user.html.haml +4 -4
  66. data/app/views/contacts/_index_brief.html.haml +1 -1
  67. data/app/views/contacts/_index_full.html.haml +1 -1
  68. data/app/views/contacts/_index_long.html.haml +1 -1
  69. data/app/views/devise/confirmations/new.html.haml +9 -0
  70. data/app/views/devise/mailer/confirmation_instructions.html.haml +4 -0
  71. data/app/views/devise/mailer/password_change.html.haml +3 -0
  72. data/app/views/devise/mailer/reset_password_instructions.html.haml +6 -0
  73. data/app/views/devise/passwords/edit.html.haml +18 -0
  74. data/app/views/devise/passwords/new.html.haml +10 -0
  75. data/app/views/devise/registrations/new.html.haml +21 -0
  76. data/app/views/devise/sessions/new.html.haml +32 -0
  77. data/app/views/layouts/_about.html.haml +5 -5
  78. data/app/views/layouts/_header.html.haml +3 -3
  79. data/app/views/layouts/admin/_header.html.haml +1 -1
  80. data/app/views/shared/_address.html.haml +5 -5
  81. data/app/views/shared/_paginate_with_per_page.html.haml +1 -0
  82. data/app/views/users/_avatar.html.haml +1 -1
  83. data/bin/bundle +1 -1
  84. data/bin/rails +1 -1
  85. data/bin/setup +38 -0
  86. data/bin/update +33 -0
  87. data/bin/yarn +13 -0
  88. data/config/application.rb +8 -6
  89. data/config/boot.rb +1 -1
  90. data/config/brakeman.ignore +2 -2
  91. data/config/database.postgres.docker.yml +5 -5
  92. data/config/environment.rb +1 -1
  93. data/config/environments/development.rb +1 -0
  94. data/config/environments/test.rb +7 -0
  95. data/config/initializers/action_mailer.rb +1 -3
  96. data/config/initializers/application_controller_renderer.rb +9 -0
  97. data/config/initializers/assets.rb +6 -11
  98. data/config/initializers/backtrace_silencers.rb +0 -6
  99. data/config/initializers/content_security_policy.rb +26 -0
  100. data/config/initializers/cookies_serializer.rb +3 -6
  101. data/config/initializers/devise.rb +289 -0
  102. data/config/initializers/filter_parameter_logging.rb +0 -5
  103. data/config/initializers/gravatar.rb +0 -1
  104. data/config/initializers/inflections.rb +0 -6
  105. data/config/initializers/mime_types.rb +1 -9
  106. data/config/initializers/new_framework_defaults_5_2.rb +40 -0
  107. data/config/initializers/relative_url_root.rb +1 -3
  108. data/config/initializers/session_store.rb +1 -3
  109. data/config/initializers/wrap_parameters.rb +4 -9
  110. data/config/locales/fat_free_crm.en-GB.yml +5 -5
  111. data/config/locales/fat_free_crm.en-US.yml +5 -5
  112. data/config/locales/fat_free_crm.fr.yml +1 -1
  113. data/config/locales/fat_free_crm.ru.yml +1 -0
  114. data/config/routes.rb +20 -9
  115. data/db/demo/users.yml +62 -81
  116. data/db/migrate/20100928030620_remove_uuid.rb +1 -2
  117. data/db/migrate/20120316045804_activities_to_versions.rb +1 -0
  118. data/db/migrate/20120510025219_add_not_null_constraints_for_timestamp_columns.rb +1 -0
  119. data/db/migrate/20180107082701_authlogic_to_devise.rb +58 -0
  120. data/db/schema.rb +48 -43
  121. data/docker-compose.yml +10 -0
  122. data/fat_free_crm.gemspec +11 -13
  123. data/lib/development_tasks/license.rake +2 -2
  124. data/lib/fat_free_crm/callback.rb +2 -2
  125. data/lib/fat_free_crm/comment_extensions.rb +2 -4
  126. data/lib/fat_free_crm/core_ext/string.rb +1 -1
  127. data/lib/fat_free_crm/engine.rb +1 -1
  128. data/lib/fat_free_crm/errors.rb +1 -1
  129. data/lib/fat_free_crm/export_csv.rb +1 -0
  130. data/lib/fat_free_crm/exportable.rb +1 -1
  131. data/lib/fat_free_crm/fields.rb +1 -1
  132. data/lib/fat_free_crm/gem_dependencies.rb +1 -1
  133. data/lib/fat_free_crm/gem_ext/simple_form/action_view_extensions/form_helper.rb +1 -3
  134. data/lib/fat_free_crm/i18n.rb +2 -2
  135. data/lib/fat_free_crm/mail_processor/base.rb +4 -10
  136. data/lib/fat_free_crm/mail_processor/dropbox.rb +5 -15
  137. data/lib/fat_free_crm/permissions.rb +7 -4
  138. data/lib/fat_free_crm/sortable.rb +1 -1
  139. data/lib/fat_free_crm/tabs.rb +2 -2
  140. data/lib/fat_free_crm/version.rb +2 -2
  141. data/lib/gravatar_image_tag.rb +7 -8
  142. data/lib/missing_translation_detector.rb +1 -0
  143. data/lib/tasks/ffcrm/missing_translations.rake +1 -0
  144. data/lib/tasks/ffcrm/setup.rake +10 -1
  145. data/lib/tasks/ffcrm/update_data.rake +2 -2
  146. data/script/rails +2 -2
  147. data/spec/controllers/admin/users_controller_spec.rb +0 -56
  148. data/spec/controllers/comments_controller_spec.rb +6 -6
  149. data/spec/controllers/entities/campaigns_controller_spec.rb +1 -1
  150. data/spec/controllers/entities/contacts_controller_spec.rb +2 -1
  151. data/spec/controllers/entities/leads_controller_spec.rb +2 -2
  152. data/spec/controllers/entities/opportunities_controller_spec.rb +1 -1
  153. data/spec/controllers/entities_controller_spec.rb +5 -0
  154. data/spec/controllers/home_controller_spec.rb +5 -5
  155. data/spec/controllers/tasks_controller_spec.rb +6 -4
  156. data/spec/controllers/users_controller_spec.rb +28 -98
  157. data/spec/factories/account_factories.rb +5 -5
  158. data/spec/factories/campaign_factories.rb +3 -3
  159. data/spec/factories/contact_factories.rb +8 -8
  160. data/spec/factories/field_factories.rb +4 -3
  161. data/spec/factories/lead_factories.rb +5 -5
  162. data/spec/factories/list_factories.rb +2 -2
  163. data/spec/factories/opportunity_factories.rb +3 -3
  164. data/spec/factories/setting_factories.rb +2 -2
  165. data/spec/factories/shared_factories.rb +11 -9
  166. data/spec/factories/task_factories.rb +7 -7
  167. data/spec/factories/user_factories.rb +16 -19
  168. data/spec/features/admin/groups_spec.rb +1 -1
  169. data/spec/features/admin/users_spec.rb +3 -1
  170. data/spec/features/campaigns_spec.rb +1 -1
  171. data/spec/features/contacts_spec.rb +1 -1
  172. data/spec/features/dashboard_spec.rb +1 -1
  173. data/spec/features/devise/sign_in_spec.rb +58 -0
  174. data/spec/features/devise/sign_up_spec.rb +36 -0
  175. data/spec/features/leads_spec.rb +1 -1
  176. data/spec/features/opportunities_overview_spec.rb +1 -1
  177. data/spec/features/opportunities_spec.rb +3 -3
  178. data/spec/features/support/browser.rb +2 -1
  179. data/spec/features/tasks_spec.rb +1 -1
  180. data/spec/helpers/admin/field_groups_helper_spec.rb +1 -1
  181. data/spec/helpers/users_helper_spec.rb +4 -4
  182. data/spec/lib/comment_extensions_spec.rb +10 -4
  183. data/spec/lib/errors_spec.rb +2 -2
  184. data/spec/lib/mail_processor/dropbox_spec.rb +1 -1
  185. data/spec/lib/mail_processor/sample_emails/dropbox.rb +8 -8
  186. data/spec/lib/permissions_spec.rb +8 -3
  187. data/spec/mailers/devise_mailer_spec.rb +35 -0
  188. data/spec/mailers/user_mailer_spec.rb +0 -26
  189. data/spec/models/entities/account_spec.rb +27 -0
  190. data/spec/models/entities/contact_spec.rb +96 -1
  191. data/spec/models/fields/custom_field_date_pair_spec.rb +4 -2
  192. data/spec/models/fields/custom_field_spec.rb +4 -2
  193. data/spec/models/observers/entity_observer_spec.rb +1 -1
  194. data/spec/models/polymorphic/version_spec.rb +7 -7
  195. data/spec/models/users/user_spec.rb +22 -26
  196. data/spec/routing/users_routing_spec.rb +30 -8
  197. data/spec/shared/controllers.rb +3 -9
  198. data/spec/spec_helper.rb +10 -2
  199. data/spec/support/assert_select.rb +1 -0
  200. data/spec/support/devise_helpers.rb +28 -0
  201. data/spec/{features/support/helpers.rb → support/feature_helpers.rb} +10 -10
  202. data/spec/support/macros.rb +4 -1
  203. data/spec/views/contacts/update.js.haml_spec.rb +1 -1
  204. data/spec/views/opportunities/update.js.haml_spec.rb +1 -1
  205. data/vendor/gems/ransack_ui-1.3.4/.gitignore +17 -0
  206. data/vendor/gems/ransack_ui-1.3.4/Gemfile +7 -0
  207. data/vendor/gems/ransack_ui-1.3.4/LICENSE.txt +22 -0
  208. data/vendor/gems/ransack_ui-1.3.4/README.md +57 -0
  209. data/vendor/gems/ransack_ui-1.3.4/Rakefile +1 -0
  210. data/vendor/gems/ransack_ui-1.3.4/app/assets/images/ransack_ui/calendar.png +0 -0
  211. data/vendor/gems/ransack_ui-1.3.4/app/assets/images/ransack_ui/delete.png +0 -0
  212. data/vendor/gems/ransack_ui-1.3.4/app/assets/javascripts/ransack/predicates.js.coffee +41 -0
  213. data/vendor/gems/ransack_ui-1.3.4/app/assets/javascripts/ransack_ui_bootstrap/button_group_select.js.coffee +26 -0
  214. data/vendor/gems/ransack_ui-1.3.4/app/assets/javascripts/ransack_ui_bootstrap/index.js.coffee +2 -0
  215. data/vendor/gems/ransack_ui-1.3.4/app/assets/javascripts/ransack_ui_jquery/index.js +2 -0
  216. data/vendor/gems/ransack_ui-1.3.4/app/assets/javascripts/ransack_ui_jquery/search_form.js.coffee.erb +499 -0
  217. data/vendor/gems/ransack_ui-1.3.4/app/assets/stylesheets/ransack_ui_bootstrap/index.css +3 -0
  218. data/vendor/gems/ransack_ui-1.3.4/app/assets/stylesheets/ransack_ui_bootstrap/search.css.scss +41 -0
  219. data/vendor/gems/ransack_ui-1.3.4/app/views/ransack_ui/_condition_fields.html.erb +15 -0
  220. data/vendor/gems/ransack_ui-1.3.4/app/views/ransack_ui/_grouping_fields.html.erb +16 -0
  221. data/vendor/gems/ransack_ui-1.3.4/app/views/ransack_ui/_search.html.erb +29 -0
  222. data/vendor/gems/ransack_ui-1.3.4/app/views/ransack_ui/_sort_fields.html.erb +4 -0
  223. data/vendor/gems/ransack_ui-1.3.4/config/locales/en.yml +24 -0
  224. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui.rb +9 -0
  225. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/adapters/active_record.rb +6 -0
  226. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/adapters/active_record/base.rb +46 -0
  227. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/controller_helpers.rb +18 -0
  228. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/rails/engine.rb +21 -0
  229. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/adapters/active_record/base.rb +47 -0
  230. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/configuration.rb +15 -0
  231. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/context.rb +9 -0
  232. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/helpers/form_builder.rb +262 -0
  233. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/nodes/attribute.rb +13 -0
  234. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/nodes/condition.rb +13 -0
  235. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/ransack_overrides/nodes/grouping.rb +20 -0
  236. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/version.rb +3 -0
  237. data/vendor/gems/ransack_ui-1.3.4/lib/ransack_ui/view_helpers.rb +30 -0
  238. data/vendor/gems/ransack_ui-1.3.4/ransack_ui.gemspec +23 -0
  239. metadata +79 -67
  240. data/app/controllers/authentications_controller.rb +0 -53
  241. data/app/models/users/authentication.rb +0 -56
  242. data/app/views/authentications/new.html.haml +0 -19
  243. data/app/views/passwords/edit.html.haml +0 -15
  244. data/app/views/passwords/new.html.haml +0 -10
  245. data/app/views/user_mailer/password_reset_instructions.html.haml +0 -6
  246. data/app/views/users/new.html.haml +0 -19
  247. data/spec/controllers/authentications_controller_spec.rb +0 -150
  248. data/spec/controllers/passwords_controller_spec.rb +0 -32
  249. data/spec/models/users/authentication_spec.rb +0 -19
  250. data/spec/support/auth_macros.rb +0 -49
  251. data/spec/views/authentications/new.haml_spec.rb +0 -31
@@ -6,7 +6,7 @@
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
8
  class HomeController < ApplicationController
9
- before_action :require_user, except: %i[timezone]
9
+ skip_before_action :authenticate_user!, only: %i[timezone]
10
10
  before_action :set_current_tab, only: :index
11
11
 
12
12
  #----------------------------------------------------------------------------
@@ -160,9 +160,7 @@ class HomeController < ApplicationController
160
160
  duration = current_user.pref[:activity_duration]
161
161
  if duration
162
162
  words = duration.split("_") # "two_weeks" => 2.weeks
163
- if %w[one two].include?(words.first) && %w[hour day days week weeks month].include?(words.last)
164
- %w[zero one two].index(words.first).send(words.last)
165
- end
163
+ %w[zero one two].index(words.first).send(words.last) if %w[one two].include?(words.first) && %w[hour day days week weeks month].include?(words.last)
166
164
  end
167
165
  end
168
166
  end
@@ -5,63 +5,7 @@
5
5
  # Fat Free CRM is freely distributable under the terms of MIT license.
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
- class PasswordsController < ApplicationController
9
- before_action :load_user_using_perishable_token, only: %i[edit update]
10
- before_action :require_no_user
11
-
12
- #----------------------------------------------------------------------------
13
- def new
14
- # <-- render new.html.haml
15
- end
16
-
17
- #----------------------------------------------------------------------------
18
- def create
19
- @user = User.find_by_email(params[:email])
20
- if @user
21
- @user.deliver_password_reset_instructions!
22
- flash[:notice] = t(:msg_pwd_instructions_sent)
23
- redirect_to root_url
24
- else
25
- flash[:notice] = t(:msg_email_not_found)
26
- redirect_to action: :new
27
- end
28
- end
29
-
30
- #----------------------------------------------------------------------------
31
- def edit
32
- # <-- render edit.html.haml
33
- end
34
-
35
- #----------------------------------------------------------------------------
36
- def update
37
- if empty_password?
38
- flash[:notice] = t(:msg_enter_new_password)
39
- render :edit
40
- elsif @user.update_attributes(params.require(:user).permit(:password, :password_confirmation))
41
- flash[:notice] = t(:msg_password_updated)
42
- redirect_to profile_url
43
- else
44
- render :edit
45
- end
46
- end
47
-
48
- private
49
-
50
- #----------------------------------------------------------------------------
51
- def load_user_using_perishable_token
52
- @user = User.find_using_perishable_token(params[:id])
53
- unless @user
54
- flash[:notice] = <<-EOS
55
- Sorry, we could not locate your user profile. Try to copy and paste the URL
56
- from your email into your browser or restart the reset password process.
57
- EOS
58
- redirect_to root_url
59
- end
60
- end
61
-
62
- #----------------------------------------------------------------------------
63
- def empty_password?
64
- (params[:user][:password] == params[:user][:password_confirmation]) &&
65
- params[:user][:password].blank? # " ".blank? == true
66
- end
8
+ class PasswordsController < Devise::PasswordsController
9
+ respond_to :html
10
+ append_view_path 'app/views/devise'
67
11
  end
@@ -5,8 +5,15 @@
5
5
  # Fat Free CRM is freely distributable under the terms of MIT license.
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
- #
9
- # Workaround for ActionDispatch::ClosedError
10
- # https://github.com/binarylogic/authlogic/issues/262#issuecomment-1804988
11
- #
12
- User.acts_as_authentic_config[:maintain_sessions] = false
8
+ class RegistrationsController < Devise::RegistrationsController
9
+ respond_to :html
10
+ append_view_path 'app/views/devise'
11
+
12
+ def edit
13
+ redirect_to profile_path
14
+ end
15
+
16
+ def after_inactive_sign_up_path_for(*)
17
+ new_user_session_path
18
+ end
19
+ end
@@ -5,11 +5,11 @@
5
5
  # Fat Free CRM is freely distributable under the terms of MIT license.
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
- require 'rubygems/package_task'
8
+ class SessionsController < Devise::SessionsController
9
+ respond_to :html
10
+ append_view_path 'app/views/devise'
9
11
 
10
- Bundler::GemHelper.install_tasks
11
-
12
- gemspec = eval(File.read('fat_free_crm.gemspec'))
13
- Gem::PackageTask.new(gemspec) do |p|
14
- p.gem_spec = gemspec
12
+ def after_sign_out_path_for(*)
13
+ new_user_session_path
14
+ end
15
15
  end
@@ -6,7 +6,6 @@
6
6
  # See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
7
7
  #------------------------------------------------------------------------------
8
8
  class TasksController < ApplicationController
9
- before_action :require_user
10
9
  before_action :set_current_tab, only: %i[index show]
11
10
  before_action :update_sidebar, only: :index
12
11
 
@@ -59,9 +58,7 @@ class TasksController < ApplicationController
59
58
  @category = Setting.unroll(:task_category)
60
59
  @asset = @task.asset if @task.asset_id?
61
60
 
62
- if params[:previous].to_s =~ /(\d+)\z/
63
- @previous = Task.tracked_by(current_user).find_by_id(Regexp.last_match[1]) || Regexp.last_match[1].to_i
64
- end
61
+ @previous = Task.tracked_by(current_user).find_by_id(Regexp.last_match[1]) || Regexp.last_match[1].to_i if params[:previous].to_s =~ /(\d+)\z/
65
62
 
66
63
  respond_with(@task)
67
64
  end
@@ -96,9 +93,7 @@ class TasksController < ApplicationController
96
93
  if @task.update_attributes(task_params)
97
94
  @task.bucket = @task.computed_bucket
98
95
  if called_from_index_page?
99
- if Task.bucket_empty?(@task_before_update.bucket, current_user, @view)
100
- @empty_bucket = @task_before_update.bucket
101
- end
96
+ @empty_bucket = @task_before_update.bucket if Task.bucket_empty?(@task_before_update.bucket, current_user, @view)
102
97
  update_sidebar
103
98
  end
104
99
  end
@@ -113,9 +108,7 @@ class TasksController < ApplicationController
113
108
  @task.destroy
114
109
 
115
110
  # Make sure bucket's div gets hidden if we're deleting last task in the bucket.
116
- if Task.bucket_empty?(params[:bucket], current_user, @view)
117
- @empty_bucket = params[:bucket]
118
- end
111
+ @empty_bucket = params[:bucket] if Task.bucket_empty?(params[:bucket], current_user, @view)
119
112
 
120
113
  update_sidebar if called_from_index_page?
121
114
  respond_with(@task)
@@ -128,9 +121,7 @@ class TasksController < ApplicationController
128
121
  @task&.update_attributes(completed_at: Time.now, completed_by: current_user.id)
129
122
 
130
123
  # Make sure bucket's div gets hidden if it's the last completed task in the bucket.
131
- if Task.bucket_empty?(params[:bucket], current_user)
132
- @empty_bucket = params[:bucket]
133
- end
124
+ @empty_bucket = params[:bucket] if Task.bucket_empty?(params[:bucket], current_user)
134
125
 
135
126
  update_sidebar unless params[:bucket].blank?
136
127
  respond_with(@task)
@@ -143,9 +134,7 @@ class TasksController < ApplicationController
143
134
  @task&.update_attributes(completed_at: nil, completed_by: nil)
144
135
 
145
136
  # Make sure bucket's div gets hidden if we're deleting last task in the bucket.
146
- if Task.bucket_empty?(params[:bucket], current_user, @view)
147
- @empty_bucket = params[:bucket]
148
- end
137
+ @empty_bucket = params[:bucket] if Task.bucket_empty?(params[:bucket], current_user, @view)
149
138
 
150
139
  update_sidebar
151
140
  respond_with(@task)
@@ -173,6 +162,7 @@ class TasksController < ApplicationController
173
162
 
174
163
  def task_params
175
164
  return {} unless params[:task]
165
+
176
166
  params.require(:task).permit(
177
167
  :user_id,
178
168
  :assigned_to,
@@ -186,7 +176,8 @@ class TasksController < ApplicationController
186
176
  :due_at,
187
177
  :completed_at,
188
178
  :deleted_at,
189
- :background_info
179
+ :background_info,
180
+ :calendar
190
181
  )
191
182
  end
192
183
 
@@ -9,6 +9,7 @@ class UsersController < ApplicationController
9
9
  before_action :set_current_tab, only: %i[show opportunities_overview] # Don't hightlight any tabs.
10
10
 
11
11
  check_authorization
12
+
12
13
  load_and_authorize_resource # handles all security
13
14
 
14
15
  respond_to :html, only: %i[show new]
@@ -21,30 +22,6 @@ class UsersController < ApplicationController
21
22
  respond_with(@user)
22
23
  end
23
24
 
24
- # GET /users/new
25
- # GET /users/new.js
26
- #----------------------------------------------------------------------------
27
- def new
28
- respond_with(@user)
29
- end
30
-
31
- # POST /users
32
- # POST /users.js
33
- #----------------------------------------------------------------------------
34
- def create
35
- if @user.save
36
- if Setting.user_signup == :needs_approval
37
- flash[:notice] = t(:msg_account_created)
38
- redirect_to login_url
39
- else
40
- flash[:notice] = t(:msg_successful_signup)
41
- redirect_back_or_default profile_url
42
- end
43
- else
44
- render :new
45
- end
46
- end
47
-
48
25
  # GET /users/1/edit.js
49
26
  #----------------------------------------------------------------------------
50
27
  def edit
@@ -77,9 +54,9 @@ class UsersController < ApplicationController
77
54
  render
78
55
  else
79
56
  if params[:avatar]
80
- avatar = Avatar.create(avatar_params)
81
- if avatar.valid?
82
- @user.avatar = avatar
57
+ @avatar = Avatar.create(avatar_params)
58
+ if @avatar.valid?
59
+ @user.avatar = @avatar
83
60
  else
84
61
  @user.avatar.errors.clear
85
62
  @user.avatar.errors.add(:image, t(:msg_bad_image_file))
@@ -104,7 +81,7 @@ class UsersController < ApplicationController
104
81
  # PUT /users/1/change_password.js
105
82
  #----------------------------------------------------------------------------
106
83
  def change_password
107
- if @user.valid_password?(params[:current_password], true) || @user.password_hash.blank?
84
+ if @user.valid_password?(params[:current_password])
108
85
  if params[:user][:password].blank?
109
86
  flash[:notice] = t(:msg_password_not_changed)
110
87
  else
@@ -138,6 +115,7 @@ class UsersController < ApplicationController
138
115
 
139
116
  def user_params
140
117
  return {} unless params[:user]
118
+
141
119
  params[:user][:email].try(:strip!)
142
120
  params[:user].permit(
143
121
  :username,
@@ -158,8 +136,9 @@ class UsersController < ApplicationController
158
136
 
159
137
  def avatar_params
160
138
  return {} unless params[:avatar]
139
+
161
140
  params[:avatar]
162
141
  .permit(:image)
163
- .merge(entity: @user)
142
+ .merge(entity: @user, user_id: @user.id)
164
143
  end
165
144
  end
@@ -27,7 +27,7 @@ module Admin::UsersHelper
27
27
  summary = []
28
28
  title_and_company = user_summary_title_and_company(user)
29
29
  summary << title_and_company unless title_and_company.blank?
30
- summary << t('pluralize.login', user.login_count) if user.current_login_at && user.login_count > 0
30
+ summary << t('pluralize.login', user.sign_in_count) if user.last_sign_in_at && user.sign_in_count.positive?
31
31
  summary << user.email
32
32
  summary << "#{t :phone_small}: #{user.phone}" unless user.phone.blank?
33
33
  summary << "#{t :mobile_small}: #{user.mobile}" unless user.mobile.blank?
@@ -18,7 +18,7 @@ module ApplicationHelper
18
18
 
19
19
  #----------------------------------------------------------------------------
20
20
  def tabless_layout?
21
- %w[authentications passwords].include?(controller.controller_name) ||
21
+ %w[sessions passwords registrations confirmations].include?(controller.controller_name) ||
22
22
  ((controller.controller_name == "users") && %w[create new].include?(controller.action_name))
23
23
  end
24
24
 
@@ -27,6 +27,7 @@ module ApplicationHelper
27
27
  def show_flash(options = { sticky: false })
28
28
  %i[error warning info notice alert].each do |type|
29
29
  next unless flash[type]
30
+
30
31
  html = content_tag(:div, h(flash[type]), id: "flash")
31
32
  flash[type] = nil
32
33
  return html << content_tag(:script, "crm.flash('#{type}', #{options[:sticky]})".html_safe, type: "text/javascript")
@@ -34,20 +35,23 @@ module ApplicationHelper
34
35
  content_tag(:p, nil, id: "flash", style: "display:none;")
35
36
  end
36
37
 
38
+ def subtitle_link(id, text, hidden)
39
+ link_to("<small>#{hidden ? '&#9658;' : '&#9660;'}</small> #{sanitize text}".html_safe,
40
+ url_for(controller: :home, action: :toggle, id: id),
41
+ remote: true,
42
+ onclick: "crm.flip_subtitle(this)")
43
+ end
44
+
37
45
  #----------------------------------------------------------------------------
38
46
  def subtitle(id, hidden = true, text = id.to_s.split("_").last.capitalize)
39
- content_tag("div",
40
- link_to("<small>#{hidden ? '&#9658;' : '&#9660;'}</small> #{sanitize text}".html_safe,
41
- url_for(controller: :home, action: :toggle, id: id),
42
- remote: true,
43
- onclick: "crm.flip_subtitle(this)"), class: "subtitle")
47
+ content_tag("div", subtitle_link(id, text, hidden), class: "subtitle")
44
48
  end
45
49
 
46
50
  #----------------------------------------------------------------------------
47
51
  def section(related, assets)
48
52
  asset = assets.to_s.singularize
49
- create_id = "create_#{asset}"
50
- select_id = "select_#{asset}"
53
+ create_id = "create_#{asset}"
54
+ select_id = "select_#{asset}"
51
55
  create_url = controller.send(:"new_#{asset}_path")
52
56
 
53
57
  html = tag(:br)
@@ -76,7 +80,7 @@ module ApplicationHelper
76
80
  #----------------------------------------------------------------------------
77
81
  def rating_select(name, options = {})
78
82
  stars = Hash[(1..5).map { |star| [star, "&#9733;" * star] }].sort
79
- options_for_select = %(<option value="0"#{options[:selected].to_i == 0 ? ' selected="selected"' : ''}>#{t :select_none}</option>)
83
+ options_for_select = %(<option value="0"#{options[:selected].to_i.zero? ? ' selected="selected"' : ''}>#{t :select_none}</option>)
80
84
  options_for_select += stars.map { |star| %(<option value="#{star.first}"#{options[:selected] == star.first ? ' selected="selected"' : ''}>#{star.last}</option>) }.join
81
85
  select_tag name, options_for_select.html_safe, options
82
86
  end
@@ -112,7 +116,6 @@ module ApplicationHelper
112
116
 
113
117
  #----------------------------------------------------------------------------
114
118
  def link_to_delete(record, options = {})
115
- object = record.is_a?(Array) ? record.last : record
116
119
  confirm = options[:confirm] || nil
117
120
 
118
121
  link_to(t(:delete) + "!",
@@ -254,7 +257,7 @@ module ApplicationHelper
254
257
  if site == :skype
255
258
  url = "callto:" + url
256
259
  else
257
- url = "http://" + url unless url.match?(/^https?:\/\//)
260
+ url = "http://" + url unless url.match?(%r{^https?://})
258
261
  end
259
262
  link_to(image_tag("#{site}.gif", size: "15x15"), h(url), "data-popup": true, title: t(:open_in_window, h(url)))
260
263
  end.compact.join("\n").html_safe
@@ -296,14 +299,12 @@ module ApplicationHelper
296
299
  # Ajax helper to pass browser timezone offset to the server.
297
300
  #----------------------------------------------------------------------------
298
301
  def get_browser_timezone_offset
299
- unless session[:timezone_offset]
300
- raw "$.get('#{timezone_path}', {offset: (new Date()).getTimezoneOffset()});"
301
- end
302
+ raw "$.get('#{timezone_path}', {offset: (new Date()).getTimezoneOffset()});" unless session[:timezone_offset]
302
303
  end
303
304
 
304
305
  # Entities can have associated avatars or gravatars. Only calls Gravatar
305
306
  # in production env. Gravatar won't serve default images if they are not
306
- # publically available: http://en.gravatar.com/site/implement/images
307
+ # publically available: https://en.gravatar.com/site/implement/images
307
308
  #----------------------------------------------------------------------------
308
309
  def avatar_for(model, args = {})
309
310
  args = { class: 'gravatar', size: :large }.merge(args)
@@ -327,17 +328,12 @@ module ApplicationHelper
327
328
 
328
329
  # Render a text field that is part of compound address.
329
330
  #----------------------------------------------------------------------------
330
- def address_field(form, object, attribute, extra_styles)
331
+ def address_field(form, attribute, extra_styles)
331
332
  hint = "#{t(attribute)}..."
332
- if object.send(attribute).blank?
333
- form.text_field(attribute,
334
- style: "margin-top: 6px; #{extra_styles}",
335
- placeholder: hint)
336
- else
337
- form.text_field(attribute,
338
- style: "margin-top: 6px; #{extra_styles}",
339
- placeholder: hint)
340
- end
333
+
334
+ form.text_field(attribute,
335
+ style: "margin-top: 6px; #{extra_styles}",
336
+ placeholder: hint)
341
337
  end
342
338
 
343
339
  # Return true if:
@@ -353,7 +349,7 @@ module ApplicationHelper
353
349
  # Helper to display links to supported data export formats.
354
350
  #----------------------------------------------------------------------------
355
351
  def links_to_export(action = :index)
356
- token = current_user.single_access_token
352
+ token = current_user.authentication_token
357
353
  url_params = { action: action }
358
354
  url_params[:id] = params[:id] unless params[:id].blank?
359
355
  url_params[:query] = params[:query] unless params[:query].blank?
@@ -389,7 +385,7 @@ module ApplicationHelper
389
385
  end
390
386
 
391
387
  def entity_filter_checkbox(name, value, count)
392
- checked = (session["#{controller_name}_filter"].present? ? session["#{controller_name}_filter"].split(",").include?(value.to_s) : count.to_i > 0)
388
+ checked = (session["#{controller_name}_filter"].present? ? session["#{controller_name}_filter"].split(",").include?(value.to_s) : count.to_i.positive?)
393
389
  url = url_for(action: :filter)
394
390
  onclick = %{
395
391
  var query = $('#query').val(),
@@ -421,7 +417,7 @@ module ApplicationHelper
421
417
  fmt_value = if email
422
418
  link_to_email(fmt_value)
423
419
  else
424
- fmt_value.gsub(/((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:\/\+#]*[\w\-\@?^=%&amp;\/\+#])?)/, "<a href=\"\\1\">\\1</a>")
420
+ fmt_value.gsub(%r{((http|ftp|https)://[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/\+#]*[\w\-\@?^=%&amp;/\+#])?)}, "<a href=\"\\1\">\\1</a>")
425
421
  end
426
422
  out << content_tag(:td, fmt_value, class: last_class)
427
423
  end
@@ -433,10 +429,7 @@ module ApplicationHelper
433
429
  def section_title(id, hidden = true, text = nil, info_text = nil)
434
430
  text = id.to_s.split("_").last.capitalize if text.nil?
435
431
  content_tag("div", class: "subtitle show_attributes") do
436
- content = link_to("<small>#{hidden ? '&#9658;' : '&#9660;'}</small> #{sanitize text}".html_safe,
437
- url_for(controller: :home, action: :toggle, id: id),
438
- remote: true,
439
- onclick: "crm.flip_subtitle(this)")
432
+ content = subtitle_link(id, text, hidden)
440
433
  content << content_tag("small", info_text.to_s, class: "subtitle_inline_info", id: "#{id}_intro", style: hidden ? "" : "display:none;")
441
434
  end
442
435
  end
@@ -455,6 +448,7 @@ module ApplicationHelper
455
448
  views = FatFreeCRM::ViewFactory.views_for(controller: controller.controller_name,
456
449
  action: show_or_index_action)
457
450
  return nil unless views.size > 1
451
+
458
452
  lis = ''.html_safe
459
453
  content_tag :ul, class: 'format-buttons' do
460
454
  views.collect do |view|
@@ -480,6 +474,7 @@ module ApplicationHelper
480
474
  # <span class="timeago" datetime="2008-07-17T09:24:17Z">July 17, 2008</span>
481
475
  def timeago(time, options = {})
482
476
  return unless time
477
+
483
478
  options[:class] ||= "timeago"
484
479
  options[:title] = time.getutc.iso8601
485
480
  content_tag(:span, I18n.l(time), options)