Class: Crm::SmsMessagesController

Inherits:
CrmController show all
Includes:
Controllers::Attachable, Controllers::SmsTab
Defined in:
app/controllers/crm/sms_messages_controller.rb

Overview

Controller: sms messages.

Constant Summary

Constants included from Controllers::Attachable

Controllers::Attachable::PUBLICATIONS_PER_PAGE

Constants included from Controllers::ReferenceFindable

Controllers::ReferenceFindable::ID_EMBEDDED_PATTERNS

Constants included from Controllers::AnalyticsEvents

Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY

Constants included from Controllers::ErrorRendering

Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES

Constants included from Www::SeoHelper

Www::SeoHelper::AWARDS, Www::SeoHelper::CA_ADDRESS, Www::SeoHelper::CA_BUSINESS_HOURS, Www::SeoHelper::CA_CONTACT_POINT, Www::SeoHelper::CA_CURRENCIES, Www::SeoHelper::CA_DESCRIPTION, Www::SeoHelper::CA_FOUNDING_DATE, Www::SeoHelper::CA_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::CA_LEGAL_NAME, Www::SeoHelper::CA_LOCAL_BUSINESS, Www::SeoHelper::CA_ONLINE_STORE, Www::SeoHelper::CA_RETURN_POLICY, Www::SeoHelper::CA_SALES_DEPARTMENT, Www::SeoHelper::CA_SERVICE_AREA, Www::SeoHelper::CA_URL, Www::SeoHelper::CA_VAT_ID, Www::SeoHelper::CA_WAREHOUSE_DEPARTMENT, Www::SeoHelper::CA_WAREHOUSE_HOURS, Www::SeoHelper::COMPANY_EMAIL, Www::SeoHelper::COMPANY_LOGO, Www::SeoHelper::COMPANY_NAME, Www::SeoHelper::COMPANY_SLOGAN, Www::SeoHelper::EXPERTISE, Www::SeoHelper::FAX_NUMBER, Www::SeoHelper::GS1_COMPANY_PREFIX, Www::SeoHelper::ISO6523_CODE, Www::SeoHelper::PAYMENT_METHODS, Www::SeoHelper::PHONE_NUMBER, Www::SeoHelper::PRIMARY_NAICS, Www::SeoHelper::REFUND_TYPE, Www::SeoHelper::RETURN_FEES, Www::SeoHelper::RETURN_METHOD, Www::SeoHelper::RETURN_POLICY_CATEGORY, Www::SeoHelper::SECONDARY_NAICS, Www::SeoHelper::SOCIAL_PROFILES, Www::SeoHelper::US_ADDRESS, Www::SeoHelper::US_BUSINESS_HOURS, Www::SeoHelper::US_CONTACT_POINT, Www::SeoHelper::US_CURRENCIES, Www::SeoHelper::US_DESCRIPTION, Www::SeoHelper::US_FOUNDING_DATE, Www::SeoHelper::US_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::US_IMAGE, Www::SeoHelper::US_LEGAL_NAME, Www::SeoHelper::US_LOCAL_BUSINESS, Www::SeoHelper::US_ONLINE_STORE, Www::SeoHelper::US_RETURN_POLICY, Www::SeoHelper::US_SALES_DEPARTMENT, Www::SeoHelper::US_SERVICE_AREA, Www::SeoHelper::US_TAX_ID, Www::SeoHelper::US_URL, Www::SeoHelper::US_WAREHOUSE_DEPARTMENT, Www::SeoHelper::US_WAREHOUSE_HOURS

Constants included from IconHelper

IconHelper::CUSTOM_ICON_MAP, IconHelper::CUSTOM_SVG_DIR, IconHelper::DEFAULT_FAMILY

Instance Method Summary collapse

Methods included from Controllers::Attachable

#attach, #publication_modal, #remove_attachment, #search_library

Methods inherited from CrmController

#access_denied, #context_id, #context_object, #crm_home_path, #current_ability, #default_url_options, #download_temp, #get_tempfile_path_for_download, #init_status_job_collector, #initialize_crm_lazy_chunks, #persist_enqueued_status_jobs, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download, #sync_admin_presence_cookie

Methods inherited from ApplicationController

#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #stamp_impersonation_context, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y

Methods included from Controllers::ReturnPathHandling

#check_for_return_path, #redirect_to_return_path_or_default

Methods included from Controllers::AnalyticsEvents

#consume_queued_analytics_events, #track_event

Methods included from Controllers::DeviceDetection

#device_detector, #is_ie?

Methods included from Controllers::SubdomainDetection

#is_crm_request?, #is_www_request?, #json_request?

Methods included from Controllers::TurboSafeRedirect

#redirect_to

Methods included from Controllers::TrackingDetection

#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?

Methods included from Controllers::AcceleratedFileSending

#send_file_accelerated, #send_upload_accelerated

Methods included from Controllers::ErrorRendering

#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback

Methods included from Controllers::TurnstileVerification

#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!

Methods included from Controllers::CloudflareCaching

edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session

Methods included from Controllers::Webpackable

#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?

Methods included from Controllers::Localizable

#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale

Methods included from Controllers::Authenticable

#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak

Methods included from ApplicationHelper

#better_number_to_currency, #check_force_logout, #check_or_cross, #check_or_times, #embedded_tab_frame_id, #error_messages, #general_disclaimer_on_product_installation_and_local_codes, #gridjs_from_html_table, #gridjs_table, #is_wy_ip, #line_break, #parent_layout, #pass_or_fail, #render_error_messages_list, #render_video_card, #resolved_auth_form_turbo_frame, #return_path_or, #safe_css_color, #set_return_path_if_present, #set_section_if_present, #tab_frame_id, #to_underscore, #track_page?, #turbo_section_wrapper, #turbo_tabs_request?, #url_on_same_domain_as_request, #widget_index_daily_focus_index_path, #working_hours?, #yes_or_no, #yes_or_no_highlighted, #yes_or_no_with_check_or_cross, #youtube_video

Methods included from UppyUploaderHelper

#file_uploader, #image_uploader, #large_file_uploader_s3, #lead_sketch_uploader, #rma_image_uploader, #rma_image_uploader_s3, #uppy_uploader, #video_uploader

Methods included from Www::ImagesHelper

#image_asset_tag, #image_asset_url

Methods included from Www::SeoHelper

#add_page_schema, #add_webpage_schema, #canada?, #company_social_links, #ensure_context_json, #json_ld_script_tag, #local_business_schema, #online_store_id, #online_store_schema, #page_main_entity, #page_main_entity_json, #render_auto_collection_page_schema, #render_collection_page_schema, #render_local_business_schema, #render_online_store_schema, #render_page_schemas, #render_page_video_schemas, #render_webpage_schema, #render_webpage_schema_with_collections, #usa?

Methods included from UrlsHelper

#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?

Methods included from IconHelper

#account_nav_icon, #fa_icon, #star_rating_html

Instance Method Details

#attach_to_partyObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'app/controllers/crm/sms_messages_controller.rb', line 184

def attach_to_party
  @sms_message = SmsMessage.find(params[:id])
  if @sms_message.inbound? && @sms_message.sender_party.nil? && (new_party_id = params.dig(:attach, :party_id).presence)
    @sms_message.sender_party_id = new_party_id
    @sms_message.save
    @sms_message.reload
    # Add this number to the party
    @sms_message.sender_party.contact_points.create!(category: ContactPoint::CELL, detail: @sms_message.sender)
    SmsMessage.match_unknown(numbers: [@sms_message.sender], party: @sms_message.sender_party)
    flash[:info] = "#{@sms_message.sender_party.full_name} attached to message"
  else
    flash[:error] = 'Message is not inbound or already has a party'
  end
  redirect_to_return_path_or_default sms_message_path(@sms_message)
end

#block_senderObject



200
201
202
203
204
205
206
207
208
# File 'app/controllers/crm/sms_messages_controller.rb', line 200

def block_sender
  @sms_message = SmsMessage.find(params[:id])
  if @sms_message.inbound?
    @sms_message.block_sender
  else
    flash[:error] = 'Can only block inbounds'
  end
  redirect_to_return_path_or_default sms_message_path(@sms_message)
end

#createObject



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/controllers/crm/sms_messages_controller.rb', line 77

def create
  # Extract our upload ids
  @sms_message = SmsMessage.new(params[:sms_message])
  authorize!(:create, @sms_message)
  @sms_message.direction = :outbound
  if @sms_message.valid? && @sms_message.send_message
    redirect_to_return_path_or_default redirect_url(@sms_message)
  else
    flash.now[:error] = "Unable to create outbound sms message. #{@sms_message.errors_to_s}"
    load_destination_numbers
    render :new, status: :unprocessable_content
  end
end

#create_customerObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'app/controllers/crm/sms_messages_controller.rb', line 144

def create_customer
  @sms_message = SmsMessage.find(params[:id])
  if @sms_message.inbound? && @sms_message.sender_party.nil?
    # Try first a match just in case
    @sms_message.match_inbound_sender
    if @sms_message.sender_party
      flash[:info] = "An existing matching party was discovered: #{@sms_message.sender_party.full_name}"
      @sms_message.save!
      redirect_to_return_path_or_default sms_message_path(@sms_message)
    else
      new_customer = {
        person_name: params.dig(:new_customer, :person_name),
        cell: @sms_message.sender,
        source_id: Source.find_by(referral_code: 'SMS'),
        country_iso: @sms_message.from_country_iso
      }
      redirect_to new_customer_identify_path(new_customer: new_customer)
    end
  else
    flash[:error] = 'Cannot create customer from message, message must be inbound and not already have a party'
    redirect_to_return_path_or_default sms_message_path(@sms_message)
  end
end

#destroyObject



125
126
127
128
129
130
131
132
133
134
135
# File 'app/controllers/crm/sms_messages_controller.rb', line 125

def destroy
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:destroy, @sms_message)
  if @sms_message.destroy
    flash[:info] = "SMS Message #{@sms_message.id} deleted"
    redirect_to_return_path_or_default redirect_url(@sms_message)
  else
    flash[:error] = "SMS Message could not be deleted. #{@sms_message.full_messages.join(', ')}"
    redirect_to_return_path_or_default sms_message_path(@sms_message)
  end
end

#destroy_and_block_senderObject



137
138
139
140
141
142
# File 'app/controllers/crm/sms_messages_controller.rb', line 137

def destroy_and_block_sender
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:destroy, @sms_message)
  @sms_message.block_sender
  destroy
end

#do_forwardObject



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'app/controllers/crm/sms_messages_controller.rb', line 224

def do_forward
  target_employee = Employee.active_employees.find_by(id: params[:target_employee_id])
  unless target_employee
    flash[:error] = 'Employee not found'
    return redirect_to_return_path_or_default sms_message_path(@sms_message)
  end

  target_number = target_employee.sms_enabled_numbers.first
  unless target_number
    flash[:error] = "#{target_employee.full_name} does not have an SMS-enabled number"
    return redirect_to_return_path_or_default sms_message_path(@sms_message)
  end

  if target_employee.id == @sms_message.recipient_party_id
    flash[:warning] = 'Message is already assigned to this employee'
    return redirect_to_return_path_or_default sms_message_path(@sms_message)
  end

  @sms_message.raw_data ||= {}
  @sms_message.raw_data['forwarded_from'] = {
    'original_recipient' => @sms_message.recipient,
    'original_recipient_party_id' => @sms_message.recipient_party_id,
    'forwarded_by' => current_user.id,
    'forwarded_at' => Time.current.iso8601
  }
  @sms_message.recipient = target_number
  @sms_message.recipient_party = target_employee
  @sms_message.unread = true
  # Skip validations: state-machine callbacks (e.g. trigger_send) must not fire
  # on a received message; only recipient, recipient_party_id, unread, and raw_data change.
  @sms_message.save!(validate: false)

  flash[:info] = "Message forwarded to #{target_employee.full_name}"
  redirect_to_return_path_or_default sms_message_path(@sms_message)
end

#editObject



65
66
67
68
69
70
71
72
73
74
75
# File 'app/controllers/crm/sms_messages_controller.rb', line 65

def edit
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:update, @sms_message)
  if @sms_message.new?
    load_destination_numbers
    render :edit
  else
    flash[:error] = 'Only messages in new state can be edited'
    redirect_to_return_path_or_default redirect_url(@sms_message)
  end
end

#forwardObject



220
221
222
# File 'app/controllers/crm/sms_messages_controller.rb', line 220

def forward
  @sms_enabled_employee_options = Employee.sms_enabled_for_select
end

#indexObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'app/controllers/crm/sms_messages_controller.rb', line 9

def index
  authorize!(:show, SmsMessage)
  if context_object
    build_sms_tab_data(context_object)
  else
    @context_object = nil
    @q = SmsMessage.ransack(params[:q])
    @q.sorts = 'created_at desc' if @q.sorts.blank?
    @return_path = sms_messages_path(q: params[:q])
    @context_sms_contact_points = ContactPoint.none
    @pagy, @sms_messages = pagy(@q.result.includes(:recipient_party, :sender_party), limit: params[:per])
  end
  respond_to do |format|
    format.html { render layout: should_render_layout? }
  end
end

#match_inbound_senderObject



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'app/controllers/crm/sms_messages_controller.rb', line 168

def match_inbound_sender
  @sms_message = SmsMessage.find(params[:id])
  if @sms_message.inbound? && @sms_message.sender_party.nil?
    @sms_message.match_inbound_sender
    if @sms_message.sender_party
      flash[:info] = "Found matching party: #{@sms_message.sender_party.full_name}"
      @sms_message.save!
    else
      flash[:warning] = 'No matching party found'
    end
  else
    flash[:error] = 'Cannot create customer from message, message must be inbound and not already have a party'
  end
  redirect_to_return_path_or_default sms_message_path(@sms_message)
end

#newObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/controllers/crm/sms_messages_controller.rb', line 46

def new
  @sms_message = SmsMessage.new(params[:sms_message] || {})
  authorize!(:create, SmsMessage)
  @original_sms_message = nil
  if params[:mark_as_read_sms_message_id].present?
    @original_sms_message = SmsMessage.find_by(id: params[:mark_as_read_sms_message_id])
    @original_sms_message&.update_attribute!(:unread, false)
  end
  # @sms_message.sender_party = current_user
  @sms_message.direction = :outbound
  if (sender = current_user.sms_enabled_numbers.first)
    @sms_message.sender ||= sender
    load_destination_numbers
  else
    flash[:error] = 'Current user not setup with a work SMS number'
    redirect_to_return_path_or_default redirect_url(@sms_message)
  end
end

#resendObject

If you resend a new message, you're just editing it
If you resend any other state of messages, it's a clone and new



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'app/controllers/crm/sms_messages_controller.rb', line 93

def resend
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:create, @sms_message)
  if @sms_message.outbound?
    load_destination_numbers
    if @sms_message.draft? # only new messages can be edited as is
      render :edit
    else # Clone and send to new
      @sms_message = @sms_message.deep_dup
      render :new
    end
  else
    flash[:error] = 'Can only resend outbound messages'
    redirect_to_return_path_or_default redirect_url(@sms_message)
  end
end

#showObject



33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/controllers/crm/sms_messages_controller.rb', line 33

def show
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:show, @sms_message)
  return unless params[:mark_as_read].to_b || (@sms_message.unread && @sms_message.recipient_party_id == current_user.id)

  @sms_message.update_attribute!(:unread, false)
  notice = <<-EOS
      Message was marked as read,
      #{view_context.link_to('undo and mark unread', toggle_unread_sms_message_path(@sms_message, return_path: @return_path), data: { turbo_method: :post })}
  EOS
  flash.now[:notice] = notice
end

#toggle_unreadObject



26
27
28
29
30
31
# File 'app/controllers/crm/sms_messages_controller.rb', line 26

def toggle_unread
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:update, SmsMessage)
  @sms_message.toggle!(:unread) if @sms_message.inbound?
  redirect_to_return_path_or_default redirect_url(@sms_message)
end

#unblock_senderObject



210
211
212
213
214
215
216
217
218
# File 'app/controllers/crm/sms_messages_controller.rb', line 210

def unblock_sender
  @sms_message = SmsMessage.find(params[:id])
  if @sms_message.unblock_sender
    flash[:info] = "Sender #{@sms_message.sender} was unblocked"
  else
    flash[:error] = "Could not unblock #{@sms_message.sender}. Could be already unblocked"
  end
  redirect_to_return_path_or_default sms_message_path(@sms_message)
end

#updateObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'app/controllers/crm/sms_messages_controller.rb', line 110

def update
  @sms_message = SmsMessage.find(params[:id])
  authorize!(:update, @sms_message)
  if @sms_message.update(params[:sms_message])
    if @sms_message.send_message
      flash[:info] = 'SMS message sent'
    else
      flash[:error] = 'Problem sending message'
    end
    redirect_to_return_path_or_default redirect_url(@sms_message)
  else
    render :edit, status: :unprocessable_content
  end
end