Class: Livechat::VisitorController

Inherits:
ApplicationController show all
Defined in:
app/controllers/livechat/visitor_controller.rb

Overview

The widget's API. Every action is scoped to the requesting visitor — the signed-in user's id, or the guest cookie token — so there is nothing to enumerate and no id to leak. Gated by config.enabled and rate-limited.

Instance Method Summary collapse

Instance Method Details

#createObject

POST widget/messages — first message starts the thread; writing into a resolved thread reopens it.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'app/controllers/livechat/visitor_controller.rb', line 38

def create
  message = nil
  # One transaction, so an invalid first message never leaves an empty
  # conversation behind.
  ActiveRecord::Base.transaction do
    conversation = find_conversation || start_conversation
    message = conversation.post_visitor_message!(params[:body].to_s.strip, files: params[:files])
  end
  refresh_context(message.conversation)
  Notifications.visitor_message(message)

  render json: { message: message.as_widget_json }, status: :created
rescue ActiveRecord::RecordInvalid => e
  render json: { errors: e.record.errors.full_messages }, status: :unprocessable_entity
end

#emailObject

POST widget/email — a guest leaves an address so replies reach them when they're gone.



56
57
58
59
60
61
62
63
64
65
# File 'app/controllers/livechat/visitor_controller.rb', line 56

def email
  conversation = find_conversation
  return head :not_found unless conversation

  if conversation.update(visitor_email: params[:email].to_s.strip.presence)
    head :no_content
  else
    render json: { errors: conversation.errors.full_messages }, status: :unprocessable_entity
  end
end

#readObject

POST widget/read — the visitor opened the panel and saw the replies.



68
69
70
71
# File 'app/controllers/livechat/visitor_controller.rb', line 68

def read
  find_conversation&.mark_read_for_visitor!
  head :no_content
end

#showObject

GET widget/conversation(?after=) — the widget's single source of truth: thread status, unread count for the launcher badge, and messages (all of them, or only those after the given id when polling).



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'app/controllers/livechat/visitor_controller.rb', line 20

def show
  conversation = find_conversation
  return render json: empty_state unless conversation

  messages = conversation.messages.chronological
  messages = messages.after_id(params[:after]) if params[:after].present?

  render json: {
    status: conversation.status,
    unread: conversation.messages.from_agent.unread.count,
    email: conversation.visitor_email.present?,
    cable: cable_payload(conversation),
    messages: messages.map(&:as_widget_json)
  }
end