Group refinements
This commit is contained in:
parent
c8ccee7ada
commit
f20cd5a53c
15 changed files with 287 additions and 23 deletions
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelCdrSignal extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_cdr_signal'
|
||||
events:
|
||||
'click .js-new': 'new'
|
||||
|
|
@ -246,4 +246,4 @@ class FormEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(error_message)
|
||||
)
|
||||
|
||||
App.Config.set('cdr_signal', { prio: 5100, name: 'Signal', parent: '#channels', target: '#channels/cdr_signal', controller: Index, permission: ['admin.channel_cdr_signal'] }, 'NavBarAdmin')
|
||||
App.Config.set('cdr_signal', { prio: 5100, name: 'Signal', parent: '#channels', target: '#channels/cdr_signal', controller: ChannelCdrSignal, permission: ['admin.channel_cdr_signal'] }, 'NavBarAdmin')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelCdrVoice extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_cdr_voice'
|
||||
events:
|
||||
'click .js-new': 'new'
|
||||
|
|
@ -246,4 +246,4 @@ class FormEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(error_message)
|
||||
)
|
||||
|
||||
App.Config.set('cdr_voice', { prio: 5100, name: 'Voice', parent: '#channels', target: '#channels/cdr_voice', controller: Index, permission: ['admin.channel_cdr_voice'] }, 'NavBarAdmin')
|
||||
App.Config.set('cdr_voice', { prio: 5100, name: 'Voice', parent: '#channels', target: '#channels/cdr_voice', controller: ChannelCdrVoice, permission: ['admin.channel_cdr_voice'] }, 'NavBarAdmin')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
class Index extends App.ControllerSubContent
|
||||
class ChannelCdrWhatsapp extends App.ControllerSubContent
|
||||
requiredPermission: 'admin.channel_cdr_whatsapp'
|
||||
events:
|
||||
'click .js-new': 'new'
|
||||
|
|
@ -246,4 +246,4 @@ class FormEdit extends App.ControllerModal
|
|||
@el.find('.alert').removeClass('hidden').text(error_message)
|
||||
)
|
||||
|
||||
App.Config.set('cdr_whatsapp', { prio: 5100, name: 'Whatsapp', parent: '#channels', target: '#channels/cdr_whatsapp', controller: Index, permission: ['admin.channel_cdr_whatsapp'] }, 'NavBarAdmin')
|
||||
App.Config.set('cdr_whatsapp', { prio: 5100, name: 'Whatsapp', parent: '#channels', target: '#channels/cdr_whatsapp', controller: ChannelCdrWhatsapp, permission: ['admin.channel_cdr_whatsapp'] }, 'NavBarAdmin')
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
return render json: {}, status: 401 if !channel || !channel.active
|
||||
return render json: {}, status: 401 if channel.options[:token] != token
|
||||
|
||||
# Handle group creation events
|
||||
if params[:event] == 'group_created'
|
||||
return update_group
|
||||
end
|
||||
|
||||
channel_id = channel.id
|
||||
|
||||
# validate input
|
||||
|
|
@ -141,6 +146,17 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
|
||||
receiver_phone_number = params[:to].strip
|
||||
sender_phone_number = params[:from].strip
|
||||
|
||||
# Check if this is a group message using the isGroup flag from bridge-worker
|
||||
# This flag is set when:
|
||||
# 1. The original message came from a Signal group
|
||||
# 2. Bridge-worker created a new group for the conversation
|
||||
# Note: We can't rely on UUID format alone because users with privacy settings
|
||||
# may have UUID identifiers instead of phone numbers
|
||||
is_group_message = params[:isGroup] == true || params[:is_group] == true
|
||||
# If it's a group message, the 'to' field contains the group ID
|
||||
group_id = is_group_message ? params[:to] : nil
|
||||
|
||||
customer = User.find_by(phone: sender_phone_number)
|
||||
customer ||= User.find_by(mobile: sender_phone_number)
|
||||
unless customer
|
||||
|
|
@ -192,13 +208,28 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
|
||||
# find ticket or create one
|
||||
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
||||
ticket = Ticket.where(customer_id: customer.id).where.not(state_id: state_ids).order(:updated_at).first
|
||||
|
||||
# For group messages, find ticket by group_id in preferences
|
||||
if is_group_message
|
||||
ticket = Ticket.joins("LEFT JOIN tickets AS t2 ON t2.preferences::jsonb -> 'cdr_signal' ->> 'group_id' = '#{group_id}'")
|
||||
.where(customer_id: customer.id)
|
||||
.where.not(state_id: state_ids)
|
||||
.where("tickets.preferences::jsonb -> 'cdr_signal' ->> 'group_id' = ?", group_id)
|
||||
.order(:updated_at)
|
||||
.first
|
||||
else
|
||||
ticket = Ticket.where(customer_id: customer.id).where.not(state_id: state_ids).order(:updated_at).first
|
||||
end
|
||||
|
||||
if ticket
|
||||
# check if title need to be updated
|
||||
ticket.title = title if ticket.title == '-'
|
||||
new_state = Ticket::State.find_by(default_create: true)
|
||||
ticket.state = Ticket::State.find_by(default_follow_up: true) if ticket.state_id != new_state.id
|
||||
else
|
||||
# Set up chat_id based on whether this is a group message
|
||||
chat_id = is_group_message ? group_id : sender_phone_number
|
||||
|
||||
ticket = Ticket.new(
|
||||
group_id: channel.group_id,
|
||||
title: title,
|
||||
|
|
@ -207,10 +238,15 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
channel_id: channel.id,
|
||||
cdr_signal: {
|
||||
bot_token: channel.options[:bot_token], # change to bot id
|
||||
chat_id: sender_phone_number
|
||||
chat_id: chat_id
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Store group_id if this is a group message
|
||||
if is_group_message
|
||||
ticket.preferences[:cdr_signal][:group_id] = group_id
|
||||
end
|
||||
end
|
||||
|
||||
ticket.save!
|
||||
|
|
@ -265,4 +301,66 @@ class ChannelsCdrSignalController < ApplicationController
|
|||
|
||||
render json: result, status: :ok
|
||||
end
|
||||
|
||||
# Webhook endpoint for receiving group creation notifications from bridge-worker
|
||||
# This is called when a Signal group is created for a conversation
|
||||
# Expected payload:
|
||||
# {
|
||||
# "event": "group_created",
|
||||
# "conversation_id": "ticket_id_or_number",
|
||||
# "original_recipient": "+1234567890",
|
||||
# "group_id": "uuid-of-signal-group",
|
||||
# "timestamp": "ISO8601 timestamp"
|
||||
# }
|
||||
def update_group
|
||||
# Validate required parameters
|
||||
errors = {}
|
||||
errors['event'] = 'required' unless params[:event].present?
|
||||
errors['conversation_id'] = 'required' unless params[:conversation_id].present?
|
||||
errors['group_id'] = 'required' unless params[:group_id].present?
|
||||
|
||||
if errors.present?
|
||||
render json: {
|
||||
errors: errors
|
||||
}, status: :bad_request
|
||||
return
|
||||
end
|
||||
|
||||
# Only handle group_created events for now
|
||||
unless params[:event] == 'group_created'
|
||||
render json: { error: 'Unsupported event type' }, status: :bad_request
|
||||
return
|
||||
end
|
||||
|
||||
# Find the ticket by ID or number
|
||||
ticket = if params[:conversation_id].to_s.match?(/^\d+$/)
|
||||
Ticket.find_by(id: params[:conversation_id])
|
||||
else
|
||||
Ticket.find_by(number: params[:conversation_id])
|
||||
end
|
||||
|
||||
unless ticket
|
||||
Rails.logger.error "Signal group update: Ticket not found for conversation_id #{params[:conversation_id]}"
|
||||
render json: { error: 'Ticket not found' }, status: :not_found
|
||||
return
|
||||
end
|
||||
|
||||
# Update ticket preferences with the group information
|
||||
ticket.preferences ||= {}
|
||||
ticket.preferences[:cdr_signal] ||= {}
|
||||
ticket.preferences[:cdr_signal][:group_id] = params[:group_id]
|
||||
ticket.preferences[:cdr_signal][:chat_id] = params[:group_id]
|
||||
ticket.preferences[:cdr_signal][:original_recipient] = params[:original_recipient] if params[:original_recipient].present?
|
||||
ticket.preferences[:cdr_signal][:group_created_at] = params[:timestamp] if params[:timestamp].present?
|
||||
|
||||
ticket.save!
|
||||
|
||||
Rails.logger.info "Signal group #{params[:group_id]} associated with ticket #{ticket.id}"
|
||||
|
||||
render json: {
|
||||
success: true,
|
||||
ticket_id: ticket.id,
|
||||
ticket_number: ticket.number
|
||||
}, status: :ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,10 +43,7 @@ class CommunicateCdrSignalJob < ApplicationJob
|
|||
has_error = false
|
||||
|
||||
begin
|
||||
result = channel.deliver(
|
||||
to: ticket.preferences[:cdr_signal][:chat_id],
|
||||
body: article.body
|
||||
)
|
||||
result = channel.deliver(article)
|
||||
rescue StandardError => e
|
||||
log_error(article, e.message)
|
||||
has_error = true
|
||||
|
|
|
|||
|
|
@ -43,10 +43,7 @@ class CommunicateCdrWhatsappJob < ApplicationJob
|
|||
has_error = false
|
||||
|
||||
begin
|
||||
result = channel.deliver(
|
||||
to: ticket.preferences[:cdr_whatsapp][:chat_id],
|
||||
body: article.body
|
||||
)
|
||||
result = channel.deliver(article)
|
||||
rescue StandardError => e
|
||||
log_error(article, e.message)
|
||||
has_error = true
|
||||
|
|
|
|||
|
|
@ -312,8 +312,21 @@ class CdrSignal
|
|||
def from_article(article)
|
||||
# sends a message from a zammad article
|
||||
|
||||
Rails.logger.debug { "Create signal message from article to '#{article[:to]}'..." }
|
||||
Rails.logger.debug { "Create signal message from article..." }
|
||||
|
||||
@api.send_message(article[:to], article[:body])
|
||||
# Get the recipient from ticket preferences
|
||||
ticket = Ticket.find_by(id: article.ticket_id)
|
||||
raise "No ticket found for article #{article.id}" unless ticket
|
||||
|
||||
recipient = ticket.preferences.dig('cdr_signal', 'chat_id')
|
||||
raise "No Signal chat_id found in ticket preferences" unless recipient
|
||||
|
||||
Rails.logger.debug { "Sending to recipient: '#{recipient}'" }
|
||||
|
||||
# Include ticket ID as conversationId for group creation callback
|
||||
options = {}
|
||||
options[:conversationId] = ticket.number if ticket
|
||||
|
||||
@api.send_message(recipient, article[:body], options)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,6 +35,12 @@ class CdrSignalApi
|
|||
end
|
||||
|
||||
def send_message(recipient, text, options = {})
|
||||
post('send', { to: recipient.to_s, message: text }.merge(parse_hash(options)))
|
||||
# Don't encode conversationId with CGI
|
||||
params = { to: recipient.to_s, message: text }
|
||||
if options[:conversationId]
|
||||
params[:conversationId] = options[:conversationId]
|
||||
options.delete(:conversationId)
|
||||
end
|
||||
post('send', params.merge(parse_hash(options)))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -312,8 +312,17 @@ class CdrWhatsapp
|
|||
def from_article(article)
|
||||
# sends a message from a zammad article
|
||||
|
||||
Rails.logger.debug { "Create whatsapp message from article to '#{article[:to]}'..." }
|
||||
Rails.logger.debug { "Create whatsapp message from article..." }
|
||||
|
||||
@api.send_message(article[:to], article[:body])
|
||||
# Get the recipient from ticket preferences
|
||||
ticket = Ticket.find_by(id: article.ticket_id)
|
||||
raise "No ticket found for article #{article.id}" unless ticket
|
||||
|
||||
recipient = ticket.preferences.dig('cdr_whatsapp', 'chat_id')
|
||||
raise "No WhatsApp chat_id found in ticket preferences" unless recipient
|
||||
|
||||
Rails.logger.debug { "Sending to recipient: '#{recipient}'" }
|
||||
|
||||
@api.send_message(recipient, article[:body])
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue