fat_free_crm 0.18.1 → 0.20.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.
- checksums.yaml +4 -4
- data/.github/workflows/brakeman-analysis.yml +46 -0
- data/.github/workflows/rubocop-analysis.yml +40 -0
- data/.github/workflows/ruby.yml +52 -0
- data/.rubocop_todo.yml +80 -173
- data/.travis.yml +17 -20
- data/CHANGELOG.md +63 -3
- data/CONTRIBUTORS.md +1 -0
- data/Dockerfile +45 -14
- data/Gemfile +21 -11
- data/Gemfile.lock +315 -263
- data/Procfile +1 -1
- data/README.md +6 -5
- data/Rakefile +1 -1
- data/SECURITY.md +11 -0
- data/app/assets/javascripts/application.js.erb +3 -0
- data/app/assets/stylesheets/application.css.erb +1 -0
- data/app/assets/stylesheets/base.scss +9 -2
- data/app/assets/stylesheets/bootstrap-custom.scss +206 -0
- data/app/assets/stylesheets/common.scss +88 -68
- data/app/assets/stylesheets/header.scss +0 -8
- data/app/controllers/admin/application_controller.rb +1 -1
- data/app/controllers/admin/field_groups_controller.rb +2 -4
- data/app/controllers/admin/fields_controller.rb +1 -1
- data/app/controllers/admin/groups_controller.rb +1 -1
- data/app/controllers/admin/tags_controller.rb +3 -5
- data/app/controllers/admin/users_controller.rb +7 -9
- data/app/controllers/application_controller.rb +21 -45
- data/app/controllers/comments_controller.rb +3 -6
- data/{config/initializers/authlogic.rb → app/controllers/confirmations_controller.rb} +4 -2
- data/app/controllers/emails_controller.rb +0 -2
- data/app/controllers/entities/accounts_controller.rb +2 -4
- data/app/controllers/entities/campaigns_controller.rb +2 -4
- data/app/controllers/entities/contacts_controller.rb +4 -24
- data/app/controllers/entities/leads_controller.rb +7 -10
- data/app/controllers/entities/opportunities_controller.rb +4 -14
- data/app/controllers/entities_controller.rb +21 -7
- data/app/controllers/home_controller.rb +5 -5
- data/app/controllers/lists_controller.rb +1 -1
- data/app/controllers/passwords_controller.rb +3 -59
- data/{spec/features/support/maintain_sessions.rb → app/controllers/registrations_controller.rb} +12 -5
- data/{lib/development_tasks/gem.rake → app/controllers/sessions_controller.rb} +6 -6
- data/app/controllers/tasks_controller.rb +11 -20
- data/app/controllers/users_controller.rb +11 -30
- data/app/helpers/accounts_helper.rb +12 -0
- data/app/helpers/admin/users_helper.rb +1 -1
- data/app/helpers/application_helper.rb +30 -37
- data/app/helpers/campaigns_helper.rb +1 -1
- data/app/helpers/contacts_helper.rb +1 -3
- data/app/helpers/opportunities_helper.rb +4 -12
- data/app/helpers/tasks_helper.rb +3 -3
- data/app/helpers/users_helper.rb +1 -3
- data/{config/initializers/paper_trail.rb → app/mailers/devise_mailer.rb} +5 -1
- data/app/mailers/user_mailer.rb +0 -9
- data/app/models/entities/account.rb +11 -11
- data/app/models/entities/account_contact.rb +1 -1
- data/app/models/entities/account_opportunity.rb +1 -1
- data/app/models/entities/campaign.rb +5 -7
- data/app/models/entities/contact.rb +25 -13
- data/app/models/entities/lead.rb +8 -8
- data/app/models/entities/opportunity.rb +8 -10
- data/app/models/fields/custom_field.rb +1 -0
- data/app/models/fields/custom_field_date_pair.rb +2 -0
- data/app/models/fields/custom_field_pair.rb +2 -2
- data/app/models/fields/field.rb +1 -3
- data/app/models/list.rb +1 -1
- data/app/models/observers/entity_observer.rb +3 -7
- data/app/models/observers/lead_observer.rb +2 -4
- data/app/models/observers/opportunity_observer.rb +3 -5
- data/app/models/observers/task_observer.rb +1 -1
- data/app/models/polymorphic/address.rb +1 -1
- data/app/models/polymorphic/comment.rb +1 -1
- data/app/models/polymorphic/email.rb +3 -3
- data/app/models/polymorphic/task.rb +14 -10
- data/app/models/polymorphic/version.rb +3 -2
- data/app/models/setting.rb +5 -1
- data/app/models/users/permission.rb +3 -3
- data/app/models/users/preference.rb +4 -3
- data/app/models/users/user.rb +67 -42
- data/app/views/accounts/_edit.html.haml +2 -2
- data/app/views/accounts/_new.html.haml +2 -2
- data/app/views/accounts/_sidebar_index.html.haml +2 -2
- data/app/views/accounts/_sidebar_show.html.haml +19 -19
- data/app/views/accounts/_top_section.html.haml +1 -1
- data/app/views/accounts/create.js.haml +1 -2
- data/app/views/accounts/destroy.js.haml +1 -1
- data/app/views/accounts/edit.js.haml +1 -1
- data/app/views/accounts/show.html.haml +1 -0
- data/app/views/accounts/update.js.haml +4 -5
- data/app/views/admin/field_groups/create.js.haml +0 -1
- data/app/views/admin/field_groups/destroy.js.haml +0 -1
- data/app/views/admin/field_groups/update.js.haml +0 -1
- data/app/views/admin/fields/create.js.haml +0 -1
- data/app/views/admin/fields/destroy.js.haml +0 -1
- data/app/views/admin/fields/update.js.haml +0 -1
- data/app/views/admin/groups/create.js.haml +0 -1
- data/app/views/admin/groups/destroy.js.haml +0 -1
- data/app/views/admin/groups/update.js.haml +0 -1
- data/app/views/admin/tags/create.js.haml +0 -1
- data/app/views/admin/tags/destroy.js.haml +0 -1
- data/app/views/admin/tags/update.js.haml +0 -1
- data/app/views/admin/users/_user.html.haml +4 -4
- data/app/views/admin/users/create.js.haml +0 -1
- data/app/views/admin/users/destroy.js.haml +0 -1
- data/app/views/admin/users/update.js.haml +0 -1
- data/app/views/campaigns/_edit.html.haml +1 -1
- data/app/views/campaigns/_new.html.haml +1 -1
- data/app/views/campaigns/_sidebar_index.html.haml +2 -2
- data/app/views/campaigns/_sidebar_show.html.haml +68 -67
- data/app/views/campaigns/create.js.haml +1 -2
- data/app/views/campaigns/destroy.js.haml +1 -1
- data/app/views/campaigns/show.html.haml +1 -0
- data/app/views/campaigns/update.js.haml +3 -4
- data/app/views/comments/_edit.html.haml +1 -1
- data/app/views/comments/_new.html.haml +1 -1
- data/app/views/comments/update.js.haml +0 -1
- data/app/views/contacts/_edit.html.haml +1 -1
- data/app/views/contacts/_index_brief.html.haml +1 -1
- data/app/views/contacts/_index_full.html.haml +1 -1
- data/app/views/contacts/_index_long.html.haml +1 -1
- data/app/views/contacts/_new.html.haml +1 -1
- data/app/views/contacts/_sidebar_show.html.haml +18 -18
- data/app/views/contacts/create.js.haml +0 -1
- data/app/views/contacts/destroy.js.haml +1 -1
- data/app/views/contacts/show.html.haml +1 -0
- data/app/views/contacts/update.js.haml +2 -3
- data/app/views/devise/confirmations/new.html.haml +9 -0
- data/app/views/devise/mailer/confirmation_instructions.html.haml +4 -0
- data/app/views/devise/mailer/password_change.html.haml +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.haml +6 -0
- data/app/views/devise/passwords/edit.html.haml +18 -0
- data/app/views/devise/passwords/new.html.haml +10 -0
- data/app/views/devise/registrations/new.html.haml +21 -0
- data/app/views/devise/sessions/new.html.haml +32 -0
- data/app/views/entities/_title_bar.html.haml +1 -1
- data/app/views/entities/attach.js.haml +2 -2
- data/app/views/entities/discard.js.haml +2 -2
- data/app/views/home/_opportunity.html.haml +1 -1
- data/app/views/home/_task.html.haml +1 -1
- data/app/views/home/index.xls.builder +51 -0
- data/app/views/layouts/_about.html.haml +5 -5
- data/app/views/layouts/_header.html.haml +3 -3
- data/app/views/layouts/_sidebar.html.haml +2 -2
- data/app/views/layouts/_tabbed.html.haml +14 -11
- data/app/views/layouts/admin/_header.html.haml +1 -1
- data/app/views/layouts/application.html.haml +2 -2
- data/app/views/leads/_edit.html.haml +2 -2
- data/app/views/leads/_new.html.haml +2 -2
- data/app/views/leads/_sidebar_index.html.haml +2 -2
- data/app/views/leads/_sidebar_show.html.haml +30 -30
- data/app/views/leads/create.js.haml +2 -3
- data/app/views/leads/destroy.js.haml +2 -2
- data/app/views/leads/promote.js.haml +3 -4
- data/app/views/leads/reject.js.haml +3 -3
- data/app/views/leads/show.html.haml +1 -1
- data/app/views/leads/update.js.haml +4 -5
- data/app/views/lists/create.js.haml +0 -1
- data/app/views/opportunities/_edit.html.haml +1 -1
- data/app/views/opportunities/_index_brief.html.haml +1 -1
- data/app/views/opportunities/_index_long.html.haml +1 -1
- data/app/views/opportunities/_new.html.haml +1 -1
- data/app/views/opportunities/_sidebar_index.html.haml +2 -2
- data/app/views/opportunities/_sidebar_show.html.haml +47 -46
- data/app/views/opportunities/create.js.haml +3 -4
- data/app/views/opportunities/destroy.js.haml +3 -3
- data/app/views/opportunities/show.html.haml +1 -0
- data/app/views/opportunities/update.js.haml +5 -6
- data/app/views/shared/_address.html.haml +5 -5
- data/app/views/shared/_empty.html.haml +1 -1
- data/app/views/shared/_inline_styles.html.haml +0 -26
- data/app/views/shared/_paginate_with_per_page.html.haml +1 -0
- data/app/views/tasks/_assigned.html.haml +1 -1
- data/app/views/tasks/_completed.html.haml +1 -1
- data/app/views/tasks/_edit.html.haml +1 -1
- data/app/views/tasks/_new.html.haml +1 -1
- data/app/views/tasks/_pending.html.haml +1 -1
- data/app/views/tasks/_related.html.haml +1 -1
- data/app/views/tasks/_selector.html.haml +7 -8
- data/app/views/tasks/_sidebar_index.html.haml +2 -2
- data/app/views/tasks/_title.html.haml +1 -1
- data/app/views/tasks/complete.js.haml +1 -1
- data/app/views/tasks/create.js.haml +1 -2
- data/app/views/tasks/destroy.js.haml +1 -1
- data/app/views/tasks/uncomplete.js.haml +1 -2
- data/app/views/tasks/update.js.haml +0 -1
- data/app/views/users/_avatar.html.haml +1 -1
- data/app/views/users/change_password.js.haml +0 -1
- data/app/views/users/update.js.haml +0 -1
- data/app/views/users/upload_avatar.js.haml +0 -1
- data/app/views/versions/_version_item.html.haml +1 -1
- data/bin/bundle +1 -1
- data/bin/rails +1 -1
- data/bin/setup +38 -0
- data/bin/update +33 -0
- data/bin/yarn +13 -0
- data/config/application.rb +8 -6
- data/config/boot.rb +1 -1
- data/config/brakeman.ignore +2 -2
- data/config/database.postgres.docker.yml +5 -5
- data/config/environment.rb +2 -2
- data/config/environments/development.rb +1 -0
- data/config/environments/test.rb +7 -0
- data/config/initializers/action_mailer.rb +1 -3
- data/config/initializers/application_controller_renderer.rb +9 -0
- data/config/initializers/assets.rb +6 -11
- data/config/initializers/backtrace_silencers.rb +0 -6
- data/config/initializers/content_security_policy.rb +31 -0
- data/config/initializers/cookies_serializer.rb +3 -6
- data/config/initializers/devise.rb +289 -0
- data/config/initializers/filter_parameter_logging.rb +0 -5
- data/config/initializers/gravatar.rb +0 -1
- data/config/initializers/inflections.rb +0 -6
- data/config/initializers/mime_types.rb +1 -9
- data/config/initializers/new_framework_defaults_6_0.rb +46 -0
- data/config/initializers/relative_url_root.rb +1 -3
- data/config/initializers/session_store.rb +1 -3
- data/config/initializers/simple_form.rb +135 -55
- data/config/initializers/simple_form_bootstrap.rb +433 -0
- data/config/initializers/wrap_parameters.rb +4 -9
- data/config/locales/fat_free_crm.cs.yml +86 -47
- data/config/locales/fat_free_crm.en-GB.yml +5 -5
- data/config/locales/fat_free_crm.en-US.yml +5 -5
- data/config/locales/fat_free_crm.fr.yml +1 -1
- data/config/locales/fat_free_crm.ru.yml +2 -0
- data/config/routes.rb +20 -9
- data/config/settings.default.yml +0 -41
- data/db/demo/users.yml +62 -81
- data/db/migrate/20100928030620_remove_uuid.rb +1 -2
- data/db/migrate/20120316045804_activities_to_versions.rb +1 -0
- data/db/migrate/20120510025219_add_not_null_constraints_for_timestamp_columns.rb +1 -0
- data/db/migrate/20180107082701_authlogic_to_devise.rb +58 -0
- data/db/migrate/20200806004152_add_pattern_to_fields.rb +7 -0
- data/db/migrate/20200806004459_add_html5_to_fields.rb +10 -0
- data/db/schema.rb +58 -48
- data/docker-compose.yml +10 -0
- data/fat_free_crm.gemspec +13 -15
- data/lib/development_tasks/license.rake +2 -2
- data/lib/fat_free_crm/callback.rb +2 -2
- data/lib/fat_free_crm/comment_extensions.rb +2 -4
- data/lib/fat_free_crm/core_ext/string.rb +1 -1
- data/lib/fat_free_crm/core_ext.rb +1 -1
- data/lib/fat_free_crm/engine.rb +1 -1
- data/lib/fat_free_crm/errors.rb +1 -1
- data/lib/fat_free_crm/export_csv.rb +1 -0
- data/lib/fat_free_crm/exportable.rb +1 -1
- data/lib/fat_free_crm/fields.rb +1 -1
- data/lib/fat_free_crm/gem_dependencies.rb +1 -1
- data/lib/fat_free_crm/gem_ext.rb +0 -1
- data/lib/fat_free_crm/i18n.rb +2 -2
- data/lib/fat_free_crm/mail_processor/base.rb +4 -10
- data/lib/fat_free_crm/mail_processor/dropbox.rb +5 -15
- data/lib/fat_free_crm/permissions.rb +7 -4
- data/lib/fat_free_crm/sortable.rb +1 -1
- data/lib/fat_free_crm/tabs.rb +2 -2
- data/lib/fat_free_crm/version.rb +2 -2
- data/lib/gravatar_image_tag.rb +8 -9
- data/lib/missing_translation_detector.rb +1 -0
- data/lib/tasks/ffcrm/missing_translations.rake +1 -0
- data/lib/tasks/ffcrm/preference_update.rake +19 -0
- data/lib/tasks/ffcrm/setup.rake +11 -2
- data/lib/tasks/ffcrm/update_data.rake +2 -2
- data/lib/templates/erb/scaffold/_form.html.erb +4 -2
- data/script/rails +2 -2
- data/spec/controllers/admin/users_controller_spec.rb +0 -56
- data/spec/controllers/comments_controller_spec.rb +12 -12
- data/spec/controllers/entities/campaigns_controller_spec.rb +1 -1
- data/spec/controllers/entities/contacts_controller_spec.rb +2 -1
- data/spec/controllers/entities/leads_controller_spec.rb +2 -2
- data/spec/controllers/entities/opportunities_controller_spec.rb +1 -1
- data/spec/controllers/entities_controller_spec.rb +5 -0
- data/spec/controllers/home_controller_spec.rb +8 -8
- data/spec/controllers/tasks_controller_spec.rb +6 -4
- data/spec/controllers/users_controller_spec.rb +41 -99
- data/spec/factories/account_factories.rb +5 -5
- data/spec/factories/campaign_factories.rb +3 -3
- data/spec/factories/contact_factories.rb +8 -8
- data/spec/factories/field_factories.rb +4 -3
- data/spec/factories/lead_factories.rb +5 -5
- data/spec/factories/list_factories.rb +2 -2
- data/spec/factories/opportunity_factories.rb +3 -3
- data/spec/factories/setting_factories.rb +2 -2
- data/spec/factories/shared_factories.rb +11 -9
- data/spec/factories/task_factories.rb +7 -7
- data/spec/factories/user_factories.rb +21 -21
- data/spec/features/acceptance_helper.rb +1 -1
- data/spec/features/accounts_spec.rb +2 -2
- data/spec/features/admin/groups_spec.rb +2 -2
- data/spec/features/admin/users_spec.rb +4 -2
- data/spec/features/campaigns_spec.rb +3 -3
- data/spec/features/contacts_spec.rb +3 -6
- data/spec/features/dashboard_spec.rb +1 -1
- data/spec/features/devise/sign_in_spec.rb +58 -0
- data/spec/features/devise/sign_up_spec.rb +36 -0
- data/spec/features/leads_spec.rb +12 -8
- data/spec/features/opportunities_overview_spec.rb +1 -1
- data/spec/features/opportunities_spec.rb +7 -7
- data/spec/features/support/browser.rb +8 -3
- data/spec/features/support/selector_helpers.rb +10 -1
- data/spec/features/tasks_spec.rb +7 -7
- data/spec/helpers/accounts_helper_spec.rb +57 -0
- data/spec/helpers/admin/field_groups_helper_spec.rb +1 -1
- data/spec/helpers/users_helper_spec.rb +4 -4
- data/spec/lib/comment_extensions_spec.rb +10 -4
- data/spec/lib/errors_spec.rb +2 -2
- data/spec/lib/mail_processor/dropbox_spec.rb +1 -1
- data/spec/lib/mail_processor/sample_emails/dropbox.rb +8 -8
- data/spec/lib/permissions_spec.rb +8 -3
- data/spec/mailers/devise_mailer_spec.rb +35 -0
- data/spec/mailers/user_mailer_spec.rb +0 -26
- data/spec/models/entities/account_spec.rb +27 -0
- data/spec/models/entities/contact_spec.rb +96 -1
- data/spec/models/entities/opportunity_spec.rb +2 -2
- data/spec/models/fields/custom_field_date_pair_spec.rb +4 -2
- data/spec/models/fields/custom_field_pair_spec.rb +2 -2
- data/spec/models/fields/custom_field_spec.rb +4 -2
- data/spec/models/observers/entity_observer_spec.rb +4 -4
- data/spec/models/polymorphic/task_spec.rb +11 -11
- data/spec/models/polymorphic/version_spec.rb +9 -9
- data/spec/models/users/preference_spec.rb +1 -1
- data/spec/models/users/user_spec.rb +22 -26
- data/spec/routing/users_routing_spec.rb +30 -8
- data/spec/shared/controllers.rb +3 -9
- data/spec/spec_helper.rb +10 -2
- data/spec/support/assert_select.rb +1 -0
- data/spec/support/devise_helpers.rb +28 -0
- data/spec/{features/support/helpers.rb → support/feature_helpers.rb} +10 -10
- data/spec/support/macros.rb +4 -1
- data/spec/views/accounts/_edit.haml_spec.rb +1 -1
- data/spec/views/accounts/_new.haml_spec.rb +1 -1
- data/spec/views/accounts/create.js.haml_spec.rb +1 -2
- data/spec/views/accounts/update.js.haml_spec.rb +2 -5
- data/spec/views/admin/field_groups/create.js.haml_spec.rb +0 -1
- data/spec/views/admin/field_groups/update.js.haml_spec.rb +0 -1
- data/spec/views/admin/users/create.js.haml_spec.rb +0 -1
- data/spec/views/admin/users/destroy.js.haml_spec.rb +0 -6
- data/spec/views/admin/users/update.js.haml_spec.rb +1 -2
- data/spec/views/campaigns/_edit.haml_spec.rb +1 -1
- data/spec/views/campaigns/_new.haml_spec.rb +1 -1
- data/spec/views/campaigns/create.js.haml_spec.rb +1 -2
- data/spec/views/campaigns/destroy.js.haml_spec.rb +0 -1
- data/spec/views/campaigns/edit.js.haml_spec.rb +2 -2
- data/spec/views/campaigns/index.js.haml_spec.rb +1 -1
- data/spec/views/campaigns/update.js.haml_spec.rb +3 -7
- data/spec/views/contacts/_edit.haml_spec.rb +1 -1
- data/spec/views/contacts/_new.haml_spec.rb +1 -1
- data/spec/views/contacts/create.js.haml_spec.rb +1 -2
- data/spec/views/contacts/edit.js.haml_spec.rb +1 -1
- data/spec/views/contacts/index.js.html_spec.rb +1 -1
- data/spec/views/contacts/update.js.haml_spec.rb +6 -10
- data/spec/views/home/index.haml_spec.rb +2 -2
- data/spec/views/leads/_edit.haml_spec.rb +1 -1
- data/spec/views/leads/_new.haml_spec.rb +1 -1
- data/spec/views/leads/create.js.haml_spec.rb +0 -3
- data/spec/views/leads/destroy.js.haml_spec.rb +0 -2
- data/spec/views/leads/promote.js.haml_spec.rb +3 -11
- data/spec/views/leads/reject.js.haml_spec.rb +0 -3
- data/spec/views/leads/update.js.haml_spec.rb +3 -11
- data/spec/views/opportunities/_edit.haml_spec.rb +1 -1
- data/spec/views/opportunities/_new.haml_spec.rb +1 -1
- data/spec/views/opportunities/create.js.haml_spec.rb +0 -2
- data/spec/views/opportunities/destroy.js.haml_spec.rb +0 -3
- data/spec/views/opportunities/update.js.haml_spec.rb +4 -12
- data/spec/views/tasks/_edit.haml_spec.rb +1 -1
- data/spec/views/tasks/complete.js.haml_spec.rb +0 -1
- data/spec/views/tasks/create.js.haml_spec.rb +0 -2
- data/spec/views/tasks/destroy.js.haml_spec.rb +0 -1
- data/spec/views/tasks/uncomplete.js.haml_spec.rb +0 -1
- data/spec/views/tasks/update.js.haml_spec.rb +1 -4
- data/spec/views/users/change_password.js.haml_spec.rb +1 -2
- data/spec/views/users/update.js.haml_spec.rb +1 -2
- data/spec/views/users/upload_avatar.js.haml_spec.rb +1 -2
- metadata +63 -77
- data/app/controllers/authentications_controller.rb +0 -53
- data/app/models/users/authentication.rb +0 -56
- data/app/views/authentications/new.html.haml +0 -19
- data/app/views/passwords/edit.html.haml +0 -15
- data/app/views/passwords/new.html.haml +0 -10
- data/app/views/user_mailer/password_reset_instructions.html.haml +0 -6
- data/app/views/users/new.html.haml +0 -19
- data/lib/fat_free_crm/gem_ext/simple_form/action_view_extensions/form_helper.rb +0 -26
- data/spec/controllers/authentications_controller_spec.rb +0 -150
- data/spec/controllers/passwords_controller_spec.rb +0 -32
- data/spec/models/users/authentication_spec.rb +0 -19
- data/spec/support/auth_macros.rb +0 -49
- data/spec/views/authentications/new.haml_spec.rb +0 -31
data/{spec/features/support/maintain_sessions.rb → app/controllers/registrations_controller.rb}
RENAMED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
8
|
+
class SessionsController < Devise::SessionsController
|
9
|
+
respond_to :html
|
10
|
+
append_view_path 'app/views/devise'
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
@@ -93,12 +90,10 @@ class TasksController < ApplicationController
|
|
93
90
|
end
|
94
91
|
|
95
92
|
respond_with(@task) do |_format|
|
96
|
-
if @task.
|
93
|
+
if @task.update(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)
|
@@ -125,12 +118,10 @@ class TasksController < ApplicationController
|
|
125
118
|
#----------------------------------------------------------------------------
|
126
119
|
def complete
|
127
120
|
@task = Task.tracked_by(current_user).find(params[:id])
|
128
|
-
@task&.
|
121
|
+
@task&.update(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)
|
@@ -140,12 +131,10 @@ class TasksController < ApplicationController
|
|
140
131
|
#----------------------------------------------------------------------------
|
141
132
|
def uncomplete
|
142
133
|
@task = Task.tracked_by(current_user).find(params[:id])
|
143
|
-
@task&.
|
134
|
+
@task&.update(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
|
@@ -55,7 +32,7 @@ class UsersController < ApplicationController
|
|
55
32
|
# PUT /users/1.js
|
56
33
|
#----------------------------------------------------------------------------
|
57
34
|
def update
|
58
|
-
@user.
|
35
|
+
@user.update(user_params)
|
59
36
|
flash[:notice] = t(:msg_user_updated)
|
60
37
|
respond_with(@user)
|
61
38
|
end
|
@@ -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]
|
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,7 +115,10 @@ class UsersController < ApplicationController
|
|
138
115
|
|
139
116
|
def user_params
|
140
117
|
return {} unless params[:user]
|
118
|
+
|
141
119
|
params[:user][:email].try(:strip!)
|
120
|
+
params[:user][:alt_email].try(:strip!)
|
121
|
+
|
142
122
|
params[:user].permit(
|
143
123
|
:username,
|
144
124
|
:email,
|
@@ -158,8 +138,9 @@ class UsersController < ApplicationController
|
|
158
138
|
|
159
139
|
def avatar_params
|
160
140
|
return {} unless params[:avatar]
|
141
|
+
|
161
142
|
params[:avatar]
|
162
143
|
.permit(:image)
|
163
|
-
.merge(entity: @user)
|
144
|
+
.merge(entity: @user, user_id: @user.id)
|
164
145
|
end
|
165
146
|
end
|
@@ -104,4 +104,16 @@ module AccountsHelper
|
|
104
104
|
end
|
105
105
|
text.html_safe
|
106
106
|
end
|
107
|
+
|
108
|
+
# We have too much logic in the account views
|
109
|
+
# - a helper that abstracts the logic to the backend
|
110
|
+
def display_value(value)
|
111
|
+
return "N/A" if value.zero?
|
112
|
+
number_to_currency(value, precision: 0)
|
113
|
+
end
|
114
|
+
|
115
|
+
def display_assigned(account)
|
116
|
+
return truncate(account.assignee.full_name, length: 16) if account.assigned_to
|
117
|
+
nil
|
118
|
+
end
|
107
119
|
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.
|
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[
|
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 ? '►' : '▼'}</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 ? '►' : '▼'}</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
|
50
|
-
select_id
|
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, "★" * star] }].sort
|
79
|
-
options_for_select = %(<option value="0"#{options[:selected].to_i
|
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
|
@@ -84,7 +88,6 @@ module ApplicationHelper
|
|
84
88
|
#----------------------------------------------------------------------------
|
85
89
|
def link_to_inline(id, url, options = {})
|
86
90
|
text = options[:text] || t(id, default: id.to_s.titleize)
|
87
|
-
text = (arrow_for(id) + text) unless options[:plain]
|
88
91
|
related = (options[:related] ? "&related=#{options[:related]}" : '')
|
89
92
|
|
90
93
|
link_to(text,
|
@@ -112,7 +115,6 @@ module ApplicationHelper
|
|
112
115
|
|
113
116
|
#----------------------------------------------------------------------------
|
114
117
|
def link_to_delete(record, options = {})
|
115
|
-
object = record.is_a?(Array) ? record.last : record
|
116
118
|
confirm = options[:confirm] || nil
|
117
119
|
|
118
120
|
link_to(t(:delete) + "!",
|
@@ -231,16 +233,15 @@ module ApplicationHelper
|
|
231
233
|
|
232
234
|
# Reresh sidebar using the action view within the current controller.
|
233
235
|
#----------------------------------------------------------------------------
|
234
|
-
def refresh_sidebar(action = nil
|
235
|
-
refresh_sidebar_for(controller.controller_name, action
|
236
|
+
def refresh_sidebar(action = nil)
|
237
|
+
refresh_sidebar_for(controller.controller_name, action)
|
236
238
|
end
|
237
239
|
|
238
240
|
# Refresh sidebar using the action view within an arbitrary controller.
|
239
241
|
#----------------------------------------------------------------------------
|
240
|
-
def refresh_sidebar_for(view, action = nil
|
242
|
+
def refresh_sidebar_for(view, action = nil)
|
241
243
|
text = ""
|
242
244
|
text += "$('#sidebar').html('#{j render(partial: 'layouts/sidebar', locals: { view: view, action: action })}');"
|
243
|
-
text += "$('##{j shake.to_s}').effect('shake', { duration:200, distance: 3 });" if shake
|
244
245
|
text.html_safe
|
245
246
|
end
|
246
247
|
|
@@ -254,7 +255,7 @@ module ApplicationHelper
|
|
254
255
|
if site == :skype
|
255
256
|
url = "callto:" + url
|
256
257
|
else
|
257
|
-
url = "http://" + url unless url.match?(
|
258
|
+
url = "http://" + url unless url.match?(%r{^https?://})
|
258
259
|
end
|
259
260
|
link_to(image_tag("#{site}.gif", size: "15x15"), h(url), "data-popup": true, title: t(:open_in_window, h(url)))
|
260
261
|
end.compact.join("\n").html_safe
|
@@ -296,14 +297,12 @@ module ApplicationHelper
|
|
296
297
|
# Ajax helper to pass browser timezone offset to the server.
|
297
298
|
#----------------------------------------------------------------------------
|
298
299
|
def get_browser_timezone_offset
|
299
|
-
unless session[:timezone_offset]
|
300
|
-
raw "$.get('#{timezone_path}', {offset: (new Date()).getTimezoneOffset()});"
|
301
|
-
end
|
300
|
+
raw "$.get('#{timezone_path}', {offset: (new Date()).getTimezoneOffset()});" unless session[:timezone_offset]
|
302
301
|
end
|
303
302
|
|
304
303
|
# Entities can have associated avatars or gravatars. Only calls Gravatar
|
305
304
|
# in production env. Gravatar won't serve default images if they are not
|
306
|
-
# publically available:
|
305
|
+
# publically available: https://en.gravatar.com/site/implement/images
|
307
306
|
#----------------------------------------------------------------------------
|
308
307
|
def avatar_for(model, args = {})
|
309
308
|
args = { class: 'gravatar', size: :large }.merge(args)
|
@@ -327,17 +326,12 @@ module ApplicationHelper
|
|
327
326
|
|
328
327
|
# Render a text field that is part of compound address.
|
329
328
|
#----------------------------------------------------------------------------
|
330
|
-
def address_field(form,
|
329
|
+
def address_field(form, attribute, extra_styles)
|
331
330
|
hint = "#{t(attribute)}..."
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
else
|
337
|
-
form.text_field(attribute,
|
338
|
-
style: "margin-top: 6px; #{extra_styles}",
|
339
|
-
placeholder: hint)
|
340
|
-
end
|
331
|
+
|
332
|
+
form.text_field(attribute,
|
333
|
+
style: "margin-top: 6px; #{extra_styles}",
|
334
|
+
placeholder: hint)
|
341
335
|
end
|
342
336
|
|
343
337
|
# Return true if:
|
@@ -353,7 +347,7 @@ module ApplicationHelper
|
|
353
347
|
# Helper to display links to supported data export formats.
|
354
348
|
#----------------------------------------------------------------------------
|
355
349
|
def links_to_export(action = :index)
|
356
|
-
token = current_user.
|
350
|
+
token = current_user.authentication_token
|
357
351
|
url_params = { action: action }
|
358
352
|
url_params[:id] = params[:id] unless params[:id].blank?
|
359
353
|
url_params[:query] = params[:query] unless params[:query].blank?
|
@@ -389,7 +383,7 @@ module ApplicationHelper
|
|
389
383
|
end
|
390
384
|
|
391
385
|
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
|
386
|
+
checked = (session["#{controller_name}_filter"].present? ? session["#{controller_name}_filter"].split(",").include?(value.to_s) : count.to_i.positive?)
|
393
387
|
url = url_for(action: :filter)
|
394
388
|
onclick = %{
|
395
389
|
var query = $('#query').val(),
|
@@ -421,7 +415,7 @@ module ApplicationHelper
|
|
421
415
|
fmt_value = if email
|
422
416
|
link_to_email(fmt_value)
|
423
417
|
else
|
424
|
-
fmt_value.gsub(
|
418
|
+
fmt_value.gsub(%r{((http|ftp|https)://[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/\+#]*[\w\-\@?^=%&/\+#])?)}, "<a href=\"\\1\">\\1</a>")
|
425
419
|
end
|
426
420
|
out << content_tag(:td, fmt_value, class: last_class)
|
427
421
|
end
|
@@ -433,10 +427,7 @@ module ApplicationHelper
|
|
433
427
|
def section_title(id, hidden = true, text = nil, info_text = nil)
|
434
428
|
text = id.to_s.split("_").last.capitalize if text.nil?
|
435
429
|
content_tag("div", class: "subtitle show_attributes") do
|
436
|
-
content =
|
437
|
-
url_for(controller: :home, action: :toggle, id: id),
|
438
|
-
remote: true,
|
439
|
-
onclick: "crm.flip_subtitle(this)")
|
430
|
+
content = subtitle_link(id, text, hidden)
|
440
431
|
content << content_tag("small", info_text.to_s, class: "subtitle_inline_info", id: "#{id}_intro", style: hidden ? "" : "display:none;")
|
441
432
|
end
|
442
433
|
end
|
@@ -455,6 +446,7 @@ module ApplicationHelper
|
|
455
446
|
views = FatFreeCRM::ViewFactory.views_for(controller: controller.controller_name,
|
456
447
|
action: show_or_index_action)
|
457
448
|
return nil unless views.size > 1
|
449
|
+
|
458
450
|
lis = ''.html_safe
|
459
451
|
content_tag :ul, class: 'format-buttons' do
|
460
452
|
views.collect do |view|
|
@@ -480,6 +472,7 @@ module ApplicationHelper
|
|
480
472
|
# <span class="timeago" datetime="2008-07-17T09:24:17Z">July 17, 2008</span>
|
481
473
|
def timeago(time, options = {})
|
482
474
|
return unless time
|
475
|
+
|
483
476
|
options[:class] ||= "timeago"
|
484
477
|
options[:title] = time.getutc.iso8601
|
485
478
|
content_tag(:span, I18n.l(time), options)
|
@@ -14,7 +14,7 @@ module CampaignsHelper
|
|
14
14
|
|
15
15
|
#----------------------------------------------------------------------------
|
16
16
|
def performance(actual, target)
|
17
|
-
if target.to_i
|
17
|
+
if target.to_i.positive? && actual.to_i.positive?
|
18
18
|
if target > actual
|
19
19
|
n = 100 - actual * 100 / target
|
20
20
|
html = content_tag(:span, "(-#{number_to_percentage(n, precision: 1)})", class: "warn")
|
@@ -12,9 +12,7 @@ module ContactsHelper
|
|
12
12
|
summary = ['']
|
13
13
|
summary << contact.title.titleize if contact.title?
|
14
14
|
summary << contact.department if contact.department?
|
15
|
-
if contact.account&.name?
|
16
|
-
summary.last += " #{t(:at)} #{contact.account.name}"
|
17
|
-
end
|
15
|
+
summary.last += " #{t(:at)} #{contact.account.name}" if contact.account&.name?
|
18
16
|
summary << contact.email if contact.email.present?
|
19
17
|
summary << "#{t(:phone_small)}: #{contact.phone}" if contact.phone.present?
|
20
18
|
summary << "#{t(:mobile_small)}: #{contact.mobile}" if contact.mobile.present?
|
@@ -51,24 +51,16 @@ module OpportunitiesHelper
|
|
51
51
|
msg = []
|
52
52
|
won_or_lost = %w[won lost].include?(opportunity.stage)
|
53
53
|
|
54
|
-
if opportunity.weighted_amount != 0
|
55
|
-
msg << content_tag(:b, number_to_currency(opportunity.weighted_amount, precision: 0))
|
56
|
-
end
|
54
|
+
msg << content_tag(:b, number_to_currency(opportunity.weighted_amount, precision: 0)) if opportunity.weighted_amount != 0
|
57
55
|
|
58
56
|
unless won_or_lost
|
59
57
|
if detailed
|
60
|
-
if opportunity.amount.to_f != 0
|
61
|
-
msg << number_to_currency(opportunity.amount.to_f, precision: 0)
|
62
|
-
end
|
58
|
+
msg << number_to_currency(opportunity.amount.to_f, precision: 0) if opportunity.amount.to_f != 0
|
63
59
|
|
64
|
-
if opportunity.discount.to_f != 0
|
65
|
-
msg << t(:discount) + ' ' + number_to_currency(opportunity.discount, precision: 0)
|
66
|
-
end
|
60
|
+
msg << t(:discount) + ' ' + number_to_currency(opportunity.discount, precision: 0) if opportunity.discount.to_f != 0
|
67
61
|
end
|
68
62
|
|
69
|
-
if opportunity.probability.to_i != 0
|
70
|
-
msg << t(:probability) + ' ' + opportunity.probability.to_s + '%'
|
71
|
-
end
|
63
|
+
msg << t(:probability) + ' ' + opportunity.probability.to_s + '%' if opportunity.probability.to_i != 0
|
72
64
|
end
|
73
65
|
|
74
66
|
msg << opportunity_closes_on_message(opportunity, won_or_lost)
|
data/app/helpers/tasks_helper.rb
CHANGED
@@ -11,7 +11,7 @@ module TasksHelper
|
|
11
11
|
#----------------------------------------------------------------------------
|
12
12
|
def task_filter_checkbox(view, filter, count)
|
13
13
|
name = "filter_by_task_#{view}"
|
14
|
-
checked = (session[name] ? session[name].split(",").include?(filter.to_s) : count
|
14
|
+
checked = (session[name] ? session[name].split(",").include?(filter.to_s) : count.positive?)
|
15
15
|
url = url_for(action: :filter, view: view)
|
16
16
|
onclick = %{
|
17
17
|
$('#loading').show();
|
@@ -128,7 +128,7 @@ module TasksHelper
|
|
128
128
|
else
|
129
129
|
text << replace_content(@task, @task.bucket)
|
130
130
|
end
|
131
|
-
text << refresh_sidebar(:index
|
131
|
+
text << refresh_sidebar(:index)
|
132
132
|
text
|
133
133
|
end
|
134
134
|
|
@@ -136,7 +136,7 @@ module TasksHelper
|
|
136
136
|
def reschedule(task)
|
137
137
|
text = hide_task_and_possibly_bucket(task, @task_before_update.bucket)
|
138
138
|
text += insert_content(task, task.bucket, @view)
|
139
|
-
text += refresh_sidebar(:index
|
139
|
+
text += refresh_sidebar(:index)
|
140
140
|
text
|
141
141
|
end
|
142
142
|
end
|
data/app/helpers/users_helper.rb
CHANGED
@@ -7,9 +7,7 @@
|
|
7
7
|
#------------------------------------------------------------------------------
|
8
8
|
module UsersHelper
|
9
9
|
def language_for(user)
|
10
|
-
if user.preference[:locale]
|
11
|
-
_locale, language = languages.detect { |locale, _language| locale == user.preference[:locale] }
|
12
|
-
end
|
10
|
+
_locale, language = languages.detect { |locale, _language| locale == user.preference[:locale] } if user.preference[:locale]
|
13
11
|
language || "English"
|
14
12
|
end
|
15
13
|
|
@@ -5,4 +5,8 @@
|
|
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
|
-
|
8
|
+
class DeviseMailer < Devise::Mailer
|
9
|
+
def template_paths
|
10
|
+
["devise/mailer"]
|
11
|
+
end
|
12
|
+
end
|
data/app/mailers/user_mailer.rb
CHANGED
@@ -6,15 +6,6 @@
|
|
6
6
|
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
7
7
|
#------------------------------------------------------------------------------
|
8
8
|
class UserMailer < ActionMailer::Base
|
9
|
-
def password_reset_instructions(user)
|
10
|
-
@edit_password_url = edit_password_url(user.perishable_token)
|
11
|
-
|
12
|
-
mail subject: "Fat Free CRM: " + I18n.t(:password_reset_instruction),
|
13
|
-
to: user.email,
|
14
|
-
from: from_address,
|
15
|
-
date: Time.now
|
16
|
-
end
|
17
|
-
|
18
9
|
def assigned_entity_notification(entity, assigner)
|
19
10
|
@entity_url = url_for(entity)
|
20
11
|
@entity_name = entity.name
|
@@ -28,8 +28,8 @@
|
|
28
28
|
#
|
29
29
|
|
30
30
|
class Account < ActiveRecord::Base
|
31
|
-
belongs_to :user
|
32
|
-
belongs_to :assignee, class_name: "User", foreign_key: :assigned_to
|
31
|
+
belongs_to :user, optional: true # TODO: Is this really optional?
|
32
|
+
belongs_to :assignee, class_name: "User", foreign_key: :assigned_to, optional: true
|
33
33
|
has_many :account_contacts, dependent: :destroy
|
34
34
|
has_many :contacts, -> { distinct }, through: :account_contacts
|
35
35
|
has_many :account_opportunities, dependent: :destroy
|
@@ -46,7 +46,7 @@ class Account < ActiveRecord::Base
|
|
46
46
|
accepts_nested_attributes_for :billing_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
47
47
|
accepts_nested_attributes_for :shipping_address, allow_destroy: true, reject_if: proc { |attributes| Address.reject_address(attributes) }
|
48
48
|
|
49
|
-
scope :state,
|
49
|
+
scope :state, lambda { |filters|
|
50
50
|
where('category IN (?)' + (filters.delete('other') ? ' OR category IS NULL' : ''), filters)
|
51
51
|
}
|
52
52
|
scope :created_by, ->(user) { where(user_id: user.id) }
|
@@ -54,7 +54,7 @@ class Account < ActiveRecord::Base
|
|
54
54
|
|
55
55
|
scope :text_search, ->(query) { ransack('name_or_email_cont' => query).result }
|
56
56
|
|
57
|
-
scope :visible_on_dashboard,
|
57
|
+
scope :visible_on_dashboard, lambda { |user|
|
58
58
|
# Show accounts which either belong to the user and are unassigned, or are assigned to the user
|
59
59
|
where('(user_id = :user_id AND assigned_to IS NULL) OR assigned_to = :user_id', user_id: user.id)
|
60
60
|
}
|
@@ -65,7 +65,7 @@ class Account < ActiveRecord::Base
|
|
65
65
|
acts_as_commentable
|
66
66
|
uses_comment_extensions
|
67
67
|
acts_as_taggable_on :tags
|
68
|
-
has_paper_trail class_name: 'Version', ignore: [:subscribed_users]
|
68
|
+
has_paper_trail versions: { class_name: 'Version' }, ignore: [:subscribed_users]
|
69
69
|
has_fields
|
70
70
|
exportable
|
71
71
|
sortable by: ["name ASC", "rating DESC", "created_at DESC", "updated_at DESC"], default: "created_at DESC"
|
@@ -91,6 +91,7 @@ class Account < ActiveRecord::Base
|
|
91
91
|
#----------------------------------------------------------------------------
|
92
92
|
def location
|
93
93
|
return "" unless self[:billing_address]
|
94
|
+
|
94
95
|
location = self[:billing_address].strip.split("\n").last
|
95
96
|
location&.gsub(/(^|\s+)\d+(:?\s+|$)/, " ")&.strip
|
96
97
|
end
|
@@ -98,9 +99,7 @@ class Account < ActiveRecord::Base
|
|
98
99
|
# Attach given attachment to the account if it hasn't been attached already.
|
99
100
|
#----------------------------------------------------------------------------
|
100
101
|
def attach!(attachment)
|
101
|
-
unless send("#{attachment.class.name.downcase}_ids").include?(attachment.id)
|
102
|
-
send(attachment.class.name.tableize) << attachment
|
103
|
-
end
|
102
|
+
send(attachment.class.name.tableize) << attachment unless send("#{attachment.class.name.downcase}_ids").include?(attachment.id)
|
104
103
|
end
|
105
104
|
|
106
105
|
# Discard given attachment from the account.
|
@@ -117,14 +116,15 @@ class Account < ActiveRecord::Base
|
|
117
116
|
#----------------------------------------------------------------------------
|
118
117
|
def self.create_or_select_for(model, params)
|
119
118
|
# Attempt to find existing account
|
120
|
-
if params[:id].present?
|
121
|
-
|
122
|
-
|
119
|
+
return Account.find(params[:id]) if params[:id].present?
|
120
|
+
|
121
|
+
if params[:name].present?
|
123
122
|
account = Account.find_by(name: params[:name])
|
124
123
|
return account if account
|
125
124
|
end
|
126
125
|
|
127
126
|
# Fallback to create new account
|
127
|
+
params[:user] = model.user if model
|
128
128
|
account = Account.new(params)
|
129
129
|
if account.access != "Lead" || model.nil?
|
130
130
|
account.save
|
@@ -21,7 +21,7 @@ class AccountContact < ActiveRecord::Base
|
|
21
21
|
belongs_to :account, counter_cache: :contacts_count
|
22
22
|
belongs_to :contact
|
23
23
|
|
24
|
-
has_paper_trail class_name: 'Version', meta: { related: :contact },
|
24
|
+
has_paper_trail versions: { class_name: 'Version' }, meta: { related: :contact },
|
25
25
|
ignore: %i[id created_at updated_at contact_id]
|
26
26
|
|
27
27
|
validates_presence_of :account_id
|
@@ -22,7 +22,7 @@ class AccountOpportunity < ActiveRecord::Base
|
|
22
22
|
belongs_to :opportunity
|
23
23
|
validates_presence_of :account_id, :opportunity_id
|
24
24
|
|
25
|
-
has_paper_trail class_name: 'Version'
|
25
|
+
has_paper_trail versions: { class_name: 'Version' }
|
26
26
|
|
27
27
|
ActiveSupport.run_load_hooks(:fat_free_crm_account_opportunity, self)
|
28
28
|
end
|