Add support for signal usernames
This commit is contained in:
parent
e9afa065b5
commit
1b5f85627c
5 changed files with 88 additions and 17 deletions
|
|
@ -10,10 +10,10 @@
|
||||||
|
|
||||||
<% if @signal_notification_enabled: %>
|
<% if @signal_notification_enabled: %>
|
||||||
<div class="js-signal-phone-container" style="<% if !@signal_has_checked: %>display: none;<% end %>">
|
<div class="js-signal-phone-container" style="<% if !@signal_has_checked: %>display: none;<% end %>">
|
||||||
<h2><%- @T('Signal Phone Number') %></h2>
|
<h2><%- @T('Signal Recipient') %></h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="signal_uid" class="form-control" value="<%= @signal_uid %>" placeholder="+1234567890">
|
<input type="text" name="signal_uid" class="form-control" value="<%= @signal_uid %>" placeholder="+1234567890 or u:username.42">
|
||||||
<p class="help-block"><%- @T('Use international format with country code (e.g., +1234567890)') %></p>
|
<p class="help-block"><%- @T('Phone number (+1234567890) or username with u: prefix (u:john.42)') %></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
||||||
|
|
@ -97,16 +97,16 @@ const schema = computed(() => {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// CDR Link: Add Signal phone number field only when Signal notifications are enabled
|
// CDR Link: Add Signal recipient field only when Signal notifications are enabled
|
||||||
// AND at least one Signal notification checkbox is selected
|
// AND at least one Signal notification checkbox is selected
|
||||||
if (signalNotificationEnabled.value && showSignalPhoneField.value) {
|
if (signalNotificationEnabled.value && showSignalPhoneField.value) {
|
||||||
baseSchema.push({
|
baseSchema.push({
|
||||||
type: 'text',
|
type: 'text',
|
||||||
name: 'signal_uid',
|
name: 'signal_uid',
|
||||||
label: __('Signal Phone Number'),
|
label: __('Signal Recipient'),
|
||||||
help: __('Use international format with country code (e.g., +1234567890). Required when Signal notifications are enabled in the matrix.'),
|
help: __('Phone number (+1234567890) or username with u: prefix (u:john.42)'),
|
||||||
props: {
|
props: {
|
||||||
placeholder: '+1234567890',
|
placeholder: '+1234567890 or u:username.42',
|
||||||
},
|
},
|
||||||
} as any)
|
} as any)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
email = get_field_value(form_data, 'email', mapping)
|
email = get_field_value(form_data, 'email', mapping)
|
||||||
raw_phone = get_field_value(form_data, 'phone', mapping)
|
raw_phone = get_field_value(form_data, 'phone', mapping)
|
||||||
raw_signal_account = get_field_value(form_data, 'signalAccount', mapping)
|
raw_signal_account = get_field_value(form_data, 'signalAccount', mapping)
|
||||||
|
raw_signal_username = get_field_value(form_data, 'signalUsername', mapping)
|
||||||
organization = get_field_value(form_data, 'organization', mapping)
|
organization = get_field_value(form_data, 'organization', mapping)
|
||||||
type_of_support = get_field_value(form_data, 'typeOfSupport', mapping)
|
type_of_support = get_field_value(form_data, 'typeOfSupport', mapping)
|
||||||
description_of_issue = get_field_value(form_data, 'descriptionOfIssue', mapping)
|
description_of_issue = get_field_value(form_data, 'descriptionOfIssue', mapping)
|
||||||
|
|
@ -39,10 +40,11 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
# Sanitize phone numbers
|
# Sanitize phone numbers
|
||||||
phone = sanitize_phone_number(raw_phone)
|
phone = sanitize_phone_number(raw_phone)
|
||||||
signal_account = sanitize_phone_number(raw_signal_account)
|
signal_account = sanitize_phone_number(raw_signal_account)
|
||||||
|
signal_username = normalize_signal_username(raw_signal_username)
|
||||||
|
|
||||||
# Validate contact info
|
# Validate contact info
|
||||||
unless email.present? || phone.present? || signal_account.present?
|
unless email.present? || phone.present? || signal_account.present? || signal_username.present?
|
||||||
raise 'At least one contact method (email, phone, or signalAccount) is required'
|
raise 'At least one contact method (email, phone, signalAccount, or signalUsername) is required'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Build ticket title
|
# Build ticket title
|
||||||
|
|
@ -60,7 +62,8 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
phone: phone,
|
phone: phone,
|
||||||
email: email,
|
email: email,
|
||||||
first_name: first_name,
|
first_name: first_name,
|
||||||
last_name: last_name
|
last_name: last_name,
|
||||||
|
signal_username: signal_username
|
||||||
)
|
)
|
||||||
|
|
||||||
Rails.logger.info "Formstack: Using customer #{customer.id} for ticket"
|
Rails.logger.info "Formstack: Using customer #{customer.id} for ticket"
|
||||||
|
|
@ -75,18 +78,20 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
article_type = Ticket::Article::Type.find_by(name: article_type_name)
|
article_type = Ticket::Article::Type.find_by(name: article_type_name)
|
||||||
|
|
||||||
# Check for Signal integration
|
# Check for Signal integration
|
||||||
|
# Use phone number if available, otherwise fall back to username
|
||||||
|
signal_recipient = signal_account.presence || signal_username
|
||||||
signal_article_type = nil
|
signal_article_type = nil
|
||||||
signal_channel_id = nil
|
signal_channel_id = nil
|
||||||
signal_bot_token = nil
|
signal_bot_token = nil
|
||||||
|
|
||||||
if signal_account.present?
|
if signal_recipient.present?
|
||||||
signal_channel = Channel.where(area: 'Signal::Number', active: true).first
|
signal_channel = Channel.where(area: 'Signal::Number', active: true).first
|
||||||
if signal_channel
|
if signal_channel
|
||||||
signal_channel_id = signal_channel.id
|
signal_channel_id = signal_channel.id
|
||||||
signal_bot_token = signal_channel.options[:bot_token]
|
signal_bot_token = signal_channel.options[:bot_token]
|
||||||
signal_article_type = Ticket::Article::Type.find_by(name: 'cdr_signal')
|
signal_article_type = Ticket::Article::Type.find_by(name: 'cdr_signal')
|
||||||
|
|
||||||
Rails.logger.info "Formstack: Found Signal channel #{signal_channel_id} for Signal ticket"
|
Rails.logger.info "Formstack: Found Signal channel #{signal_channel_id} for Signal ticket (recipient: #{signal_recipient})"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -102,15 +107,15 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
ticket_data.merge!(zammad_fields)
|
ticket_data.merge!(zammad_fields)
|
||||||
|
|
||||||
# Add Signal preferences if applicable
|
# Add Signal preferences if applicable
|
||||||
if signal_channel_id && signal_bot_token && signal_article_type && signal_account
|
if signal_channel_id && signal_bot_token && signal_article_type && signal_recipient
|
||||||
ticket_data[:preferences] = {
|
ticket_data[:preferences] = {
|
||||||
channel_id: signal_channel_id,
|
channel_id: signal_channel_id,
|
||||||
cdr_signal: {
|
cdr_signal: {
|
||||||
bot_token: signal_bot_token,
|
bot_token: signal_bot_token,
|
||||||
chat_id: signal_account
|
chat_id: signal_recipient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Rails.logger.info "Formstack: Adding Signal preferences to ticket"
|
Rails.logger.info "Formstack: Adding Signal preferences to ticket (chat_id: #{signal_recipient})"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create ticket
|
# Create ticket
|
||||||
|
|
@ -267,7 +272,7 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_or_create_customer(phone:, email:, first_name:, last_name:)
|
def find_or_create_customer(phone:, email:, first_name:, last_name:, signal_username: nil)
|
||||||
customer = nil
|
customer = nil
|
||||||
|
|
||||||
# Try phone first
|
# Try phone first
|
||||||
|
|
@ -284,6 +289,11 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Try Signal username
|
||||||
|
if customer.nil? && signal_username.present?
|
||||||
|
customer = User.find_by(signal_username: signal_username)
|
||||||
|
end
|
||||||
|
|
||||||
# Create new customer if not found
|
# Create new customer if not found
|
||||||
unless customer
|
unless customer
|
||||||
user_data = {
|
user_data = {
|
||||||
|
|
@ -296,14 +306,31 @@ class CreateTicketFromFormJob < ApplicationJob
|
||||||
}
|
}
|
||||||
user_data[:email] = email if email.present?
|
user_data[:email] = email if email.present?
|
||||||
user_data[:phone] = phone if phone.present?
|
user_data[:phone] = phone if phone.present?
|
||||||
|
user_data[:signal_username] = signal_username if signal_username.present?
|
||||||
|
|
||||||
customer = User.create!(user_data)
|
customer = User.create!(user_data)
|
||||||
Rails.logger.info "Formstack: Created new customer #{customer.id}"
|
Rails.logger.info "Formstack: Created new customer #{customer.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Update existing customer if they don't have username
|
||||||
|
if customer && signal_username.present? && customer.signal_username.blank?
|
||||||
|
customer.update!(signal_username: signal_username)
|
||||||
|
Rails.logger.info "Formstack: Updated customer #{customer.id} with signal_username"
|
||||||
|
end
|
||||||
|
|
||||||
customer
|
customer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def normalize_signal_username(raw_username)
|
||||||
|
return nil unless raw_username.present?
|
||||||
|
|
||||||
|
username = raw_username.to_s.strip
|
||||||
|
return nil if username.empty?
|
||||||
|
|
||||||
|
# Add u: prefix if not present
|
||||||
|
username.start_with?('u:') ? username : "u:#{username}"
|
||||||
|
end
|
||||||
|
|
||||||
def get_zammad_field_values(form_data, mapping)
|
def get_zammad_field_values(form_data, mapping)
|
||||||
result = {}
|
result = {}
|
||||||
zammad_fields = mapping['zammadFields'] || {}
|
zammad_fields = mapping['zammadFields'] || {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddSignalUsername < ActiveRecord::Migration[5.2]
|
||||||
|
def self.up
|
||||||
|
add_column :users, :signal_username, :string, limit: 50
|
||||||
|
add_index :users, :signal_username
|
||||||
|
User.reset_column_information
|
||||||
|
|
||||||
|
ObjectManager::Attribute.add(
|
||||||
|
force: true,
|
||||||
|
object: 'User',
|
||||||
|
name: 'signal_username',
|
||||||
|
display: 'Signal Username',
|
||||||
|
data_type: 'input',
|
||||||
|
data_option: {
|
||||||
|
type: 'text',
|
||||||
|
maxlength: 50,
|
||||||
|
null: true,
|
||||||
|
item_class: 'formGroup--halfSize',
|
||||||
|
},
|
||||||
|
editable: false,
|
||||||
|
active: true,
|
||||||
|
screens: {
|
||||||
|
signup: {},
|
||||||
|
invite_agent: {},
|
||||||
|
invite_customer: {},
|
||||||
|
edit: { '-all-' => { null: true } },
|
||||||
|
create: { '-all-' => { null: true } },
|
||||||
|
view: { '-all-' => { shown: true } }
|
||||||
|
},
|
||||||
|
to_create: false,
|
||||||
|
to_migrate: false,
|
||||||
|
to_delete: false,
|
||||||
|
position: 721,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
ObjectManager::Attribute.find_by(name: 'signal_username', object: ObjectLookup.find_by(name: 'User'))&.destroy
|
||||||
|
remove_column :users, :signal_username
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -333,7 +333,7 @@ class CdrSignal
|
||||||
# Use Signal CLI API
|
# Use Signal CLI API
|
||||||
api = CdrSignalApi.new
|
api = CdrSignalApi.new
|
||||||
|
|
||||||
# Check if we need to create a group (auto-groups enabled, recipient is a phone number)
|
# Check if we need to create a group (auto-groups enabled, recipient is not already a group)
|
||||||
is_group_id = recipient.start_with?('group.')
|
is_group_id = recipient.start_with?('group.')
|
||||||
final_recipient = recipient
|
final_recipient = recipient
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue