diff --git a/packages/zammad-addon-link/src/app/assets/javascripts/app/views/profile/notification.jst.eco b/packages/zammad-addon-link/src/app/assets/javascripts/app/views/profile/notification.jst.eco index 65e43f9..23a563b 100644 --- a/packages/zammad-addon-link/src/app/assets/javascripts/app/views/profile/notification.jst.eco +++ b/packages/zammad-addon-link/src/app/assets/javascripts/app/views/profile/notification.jst.eco @@ -10,10 +10,10 @@ <% if @signal_notification_enabled: %>
<% end %> diff --git a/packages/zammad-addon-link/src/app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue b/packages/zammad-addon-link/src/app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue index 5b186b5..c7cd4f2 100644 --- a/packages/zammad-addon-link/src/app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue +++ b/packages/zammad-addon-link/src/app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue @@ -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 if (signalNotificationEnabled.value && showSignalPhoneField.value) { baseSchema.push({ type: 'text', name: 'signal_uid', - label: __('Signal Phone Number'), - help: __('Use international format with country code (e.g., +1234567890). Required when Signal notifications are enabled in the matrix.'), + label: __('Signal Recipient'), + help: __('Phone number (+1234567890) or username with u: prefix (u:john.42)'), props: { - placeholder: '+1234567890', + placeholder: '+1234567890 or u:username.42', }, } as any) } diff --git a/packages/zammad-addon-link/src/app/jobs/create_ticket_from_form_job.rb b/packages/zammad-addon-link/src/app/jobs/create_ticket_from_form_job.rb index ad4c929..685bcd0 100644 --- a/packages/zammad-addon-link/src/app/jobs/create_ticket_from_form_job.rb +++ b/packages/zammad-addon-link/src/app/jobs/create_ticket_from_form_job.rb @@ -32,6 +32,7 @@ class CreateTicketFromFormJob < ApplicationJob email = get_field_value(form_data, 'email', mapping) raw_phone = get_field_value(form_data, 'phone', 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) type_of_support = get_field_value(form_data, 'typeOfSupport', mapping) description_of_issue = get_field_value(form_data, 'descriptionOfIssue', mapping) @@ -39,10 +40,11 @@ class CreateTicketFromFormJob < ApplicationJob # Sanitize phone numbers phone = sanitize_phone_number(raw_phone) signal_account = sanitize_phone_number(raw_signal_account) + signal_username = normalize_signal_username(raw_signal_username) # Validate contact info - unless email.present? || phone.present? || signal_account.present? - raise 'At least one contact method (email, phone, or signalAccount) is required' + unless email.present? || phone.present? || signal_account.present? || signal_username.present? + raise 'At least one contact method (email, phone, signalAccount, or signalUsername) is required' end # Build ticket title @@ -60,7 +62,8 @@ class CreateTicketFromFormJob < ApplicationJob phone: phone, email: email, 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" @@ -75,18 +78,20 @@ class CreateTicketFromFormJob < ApplicationJob article_type = Ticket::Article::Type.find_by(name: article_type_name) # 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_channel_id = nil signal_bot_token = nil - if signal_account.present? + if signal_recipient.present? signal_channel = Channel.where(area: 'Signal::Number', active: true).first if signal_channel signal_channel_id = signal_channel.id signal_bot_token = signal_channel.options[:bot_token] 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 @@ -102,15 +107,15 @@ class CreateTicketFromFormJob < ApplicationJob ticket_data.merge!(zammad_fields) # 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] = { channel_id: signal_channel_id, cdr_signal: { 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 # Create ticket @@ -267,7 +272,7 @@ class CreateTicketFromFormJob < ApplicationJob nil 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 # Try phone first @@ -284,6 +289,11 @@ class CreateTicketFromFormJob < ApplicationJob 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 unless customer user_data = { @@ -296,14 +306,31 @@ class CreateTicketFromFormJob < ApplicationJob } user_data[:email] = email if email.present? user_data[:phone] = phone if phone.present? + user_data[:signal_username] = signal_username if signal_username.present? customer = User.create!(user_data) Rails.logger.info "Formstack: Created new customer #{customer.id}" 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 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) result = {} zammad_fields = mapping['zammadFields'] || {} diff --git a/packages/zammad-addon-link/src/db/addon/link/20260212000001_add_signal_username.rb b/packages/zammad-addon-link/src/db/addon/link/20260212000001_add_signal_username.rb new file mode 100644 index 0000000..4f3dd29 --- /dev/null +++ b/packages/zammad-addon-link/src/db/addon/link/20260212000001_add_signal_username.rb @@ -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 diff --git a/packages/zammad-addon-link/src/lib/cdr_signal.rb b/packages/zammad-addon-link/src/lib/cdr_signal.rb index d7e4d29..7f2cef4 100644 --- a/packages/zammad-addon-link/src/lib/cdr_signal.rb +++ b/packages/zammad-addon-link/src/lib/cdr_signal.rb @@ -333,7 +333,7 @@ class CdrSignal # Use Signal CLI API 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.') final_recipient = recipient