summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/ability.rb10
-rw-r--r--app/models/acd_agent.rb9
-rw-r--r--app/models/automatic_call_distributor.rb2
-rw-r--r--app/models/backup_job.rb2
-rw-r--r--app/models/call.rb24
-rw-r--r--app/models/call_route.rb18
-rw-r--r--app/models/conference.rb49
-rw-r--r--app/models/conference_invitee.rb19
-rw-r--r--app/models/gateway.rb27
-rw-r--r--app/models/gateway_setting.rb5
-rw-r--r--app/models/hunt_group.rb3
-rw-r--r--app/models/intruder.rb24
-rw-r--r--app/models/ringtone.rb2
-rw-r--r--app/models/sip_account.rb45
-rw-r--r--app/models/softkey.rb23
-rw-r--r--app/models/switchboard.rb16
-rw-r--r--app/models/switchboard_entry.rb31
-rw-r--r--app/models/user.rb4
18 files changed, 281 insertions, 32 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 3cd1d4d..2dd96b8 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -170,6 +170,11 @@ class Ability
can :manage, Ringtone, :ringtoneable_type => 'SipAccount', :ringtoneable_id => user.sip_account_ids
can :create, Ringtone
+ # User can read and toggle status of ACD agents
+ #
+ can :read, AcdAgent, :destination_type => 'SipAccount', :destination_id => user.sip_account_ids
+ can :toggle, AcdAgent, :destination_type => 'SipAccount', :destination_id => user.sip_account_ids
+
# SoftkeyFunctions
#
can :read, SoftkeyFunction
@@ -178,6 +183,11 @@ class Ability
#
can :manage, VoicemailMessage
can :manage, VoicemailSetting
+
+ # Switchboard
+ #
+ can :read, Switchboard, :id => user.switchboard_ids
+ can :read, SwitchboardEntry, :switchboard_id => user.switchboard_ids
end
end
else
diff --git a/app/models/acd_agent.rb b/app/models/acd_agent.rb
index 4be4700..61899f8 100644
--- a/app/models/acd_agent.rb
+++ b/app/models/acd_agent.rb
@@ -20,6 +20,15 @@ class AcdAgent < ActiveRecord::Base
self.name || I18n.t('acd_agents.name') + ' ID ' + self.id.to_s
end
+ def toggle_status
+ if self.status == 'active'
+ self.status = 'inactive'
+ else
+ self.status = 'active'
+ end
+ return self.save
+ end
+
private
def set_presence
dialplan_function = nil
diff --git a/app/models/automatic_call_distributor.rb b/app/models/automatic_call_distributor.rb
index 5807757..b9d7c51 100644
--- a/app/models/automatic_call_distributor.rb
+++ b/app/models/automatic_call_distributor.rb
@@ -5,6 +5,8 @@ class AutomaticCallDistributor < ActiveRecord::Base
has_many :acd_agents, :dependent => :destroy
has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy
+ has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy
+
accepts_nested_attributes_for :phone_numbers,
:reject_if => lambda { |phone_number| phone_number[:number].blank? },
:allow_destroy => true
diff --git a/app/models/backup_job.rb b/app/models/backup_job.rb
index 48dd27e..9cb4f53 100644
--- a/app/models/backup_job.rb
+++ b/app/models/backup_job.rb
@@ -37,7 +37,7 @@ class BackupJob < ActiveRecord::Base
if tmp_backup_directory.blank?
self.state = 'failed'
else
- system "cd #{backup_directory} && sudo /bin/tar czf #{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz #{File.basename(tmp_backup_directory)}"
+ system "cd #{backup_directory} && nice -n 19 sudo /bin/tar czf #{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz #{File.basename(tmp_backup_directory)}"
require 'fileutils'
FileUtils.rm_rf tmp_backup_directory
file = File::Stat.new("#{backup_directory}/#{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz")
diff --git a/app/models/call.rb b/app/models/call.rb
index 8f657fa..a8a0d7f 100644
--- a/app/models/call.rb
+++ b/app/models/call.rb
@@ -39,6 +39,30 @@ class Call < ActiveRecord::Base
return FreeswitchAPI.execute('uuid_kill', self.uuid, true);
end
+ def transfer_blind(destination, call_leg=:aleg, auth_account=nil)
+ if destination.blank?
+ return nil
+ end
+
+ if call_leg == :bleg
+ channel_uuid = self.b_uuid
+ else
+ channel_uuid = self.uuid
+ end
+
+ if channel_uuid.blank?
+ return nil
+ end
+
+ require 'freeswitch_event'
+ if auth_account
+ FreeswitchAPI.api('uuid_setvar', channel_uuid, 'gs_auth_account_type', auth_account.class.name)
+ FreeswitchAPI.api('uuid_setvar', channel_uuid, 'gs_auth_account_uuid', auth_account.uuid)
+ end
+
+ return FreeswitchAPI.api_result(FreeswitchAPI.api('uuid_transfer', channel_uuid, destination))
+ end
+
def get_variable_from_uuid(channel_uuid, variable_name)
if channel_uuid.blank?
return nil
diff --git a/app/models/call_route.rb b/app/models/call_route.rb
index 8bc811a..590d49b 100644
--- a/app/models/call_route.rb
+++ b/app/models/call_route.rb
@@ -7,7 +7,7 @@ class CallRoute < ActiveRecord::Base
has_many :route_elements, :dependent => :destroy, :order => :position
validates :name,
- :presence => true
+ :presence => true
validates :routing_table,
:presence => true,
@@ -253,4 +253,20 @@ class CallRoute < ActiveRecord::Base
end
end
+
+ def self.test_route(table, caller)
+ arguments = ["'#{table}' table"]
+ caller.each do |key, value|
+ arguments << "'#{value}' '#{key}'"
+ end
+
+ require 'freeswitch_event'
+ result = FreeswitchAPI.api_result(FreeswitchAPI.api('lua', 'test_route.lua', arguments.join(' ')))
+ if result.blank? then
+ return
+ end
+
+ return JSON.parse(result)
+ end
+
end
diff --git a/app/models/conference.rb b/app/models/conference.rb
index aee75d5..a9d6708 100644
--- a/app/models/conference.rb
+++ b/app/models/conference.rb
@@ -7,6 +7,12 @@ class Conference < ActiveRecord::Base
has_many :conference_invitees, :dependent => :destroy
has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy
+ before_validation {
+ if !self.pin.blank?
+ self.pin = self.pin.to_s.gsub(/[^0-9]/, '')
+ end
+ }
+
validates_presence_of :conferenceable_type, :conferenceable_id
validates_presence_of :conferenceable
validates_presence_of :name
@@ -21,15 +27,12 @@ class Conference < ActiveRecord::Base
validates_inclusion_of :open_for_anybody, :in => [true, false]
- validates_numericality_of :pin, :only_integer => true,
- :greater_than => 0,
- :allow_nil => true,
- :allow_blank => true
validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')),
:allow_nil => true,
:allow_blank => true
validate :start_and_end_dates_must_make_sense, :if => Proc.new { |conference| !conference.start.blank? && !conference.end.blank? }
+
before_save :send_pin_email_when_pin_has_changed
@@ -46,11 +49,45 @@ class Conference < ActiveRecord::Base
def to_s
name
end
+
+ def list_conference
+ require 'freeswitch_event'
+ result = FreeswitchAPI.api_result(FreeswitchAPI.api('conference', "conference#{self.id}", 'xml_list'))
+ if result =~ /^\<\?xml/
+ data = Hash.from_xml(result)
+ if data
+ return data.fetch('conferences',{}).fetch('conference',{})
+ end
+ end
+ return nil
+ end
+
+ def list_members(data=self.list_conference())
+ if data.blank?
+ return {}
+ end
+
+ members = data.fetch('members',{}).fetch('member',{})
+ if members.class != Array
+ members = [members]
+ end
+
+ members.each_with_index do |member, index|
+ members[index][:call] = Call.where(:uuid => member['uuid']).first
+ if !members[index][:call]
+ members[index][:call] = Call.where(:b_uuid => member['uuid']).first
+ if members[index][:call]
+ members[index][:call_bleg] = true;
+ end
+ end
+ end
+
+ return members;
+ end
+
private
-
def start_and_end_dates_must_make_sense
- errors.add(:start, 'must be in the future') if self.start < Time.now - 10.minutes
errors.add(:end, 'must be later than the start') if self.end < self.start
end
diff --git a/app/models/conference_invitee.rb b/app/models/conference_invitee.rb
index d6e3bac..5b99ca4 100644
--- a/app/models/conference_invitee.rb
+++ b/app/models/conference_invitee.rb
@@ -1,27 +1,28 @@
class ConferenceInvitee < ActiveRecord::Base
attr_accessible :pin, :speaker, :moderator, :phone_number, :phone_number_attributes
-
+
belongs_to :conference
belongs_to :phone_book_entry
has_one :phone_number, :as => :phone_numberable, :dependent => :destroy
accepts_nested_attributes_for :phone_number
+ before_validation {
+ if !self.pin.blank?
+ self.pin = self.pin.to_s.gsub(/[^0-9]/, '')
+ end
+ }
+
validates_presence_of :conference_id
validates_presence_of :conference
validates_presence_of :phone_number
- validates_numericality_of :pin, :only_integer => true,
- :greater_than => 0,
- :allow_nil => true,
- :allow_blank => true
- validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')),
- :allow_nil => true,
- :allow_blank => true
+ validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')),
+ :allow_nil => true,
+ :allow_blank => true
validates_inclusion_of :speaker, :in => [true, false]
validates_inclusion_of :moderator, :in => [true, false]
validate :uniqueness_of_phone_number_in_the_parent_conference
- validates_uniqueness_of :phone_book_entry_id, :scope => :conference_id, :allow_nil => true
def to_s
"ID #{self.id}"
diff --git a/app/models/gateway.rb b/app/models/gateway.rb
index 2f17b57..bf391fb 100644
--- a/app/models/gateway.rb
+++ b/app/models/gateway.rb
@@ -27,7 +27,34 @@ class Gateway < ActiveRecord::Base
"#{GATEWAY_PREFIX}#{self.id}"
end
+ def status
+ if self.technology == 'sip' then
+ return status_sip
+ end
+ end
+
+ def inbound_register
+ username = self.gateway_settings.where(:name => 'inbound_username').first.try(:value)
+ if username.blank?
+ return
+ end
+
+ return SipRegistration.where(:sip_user => username).first
+ end
+
private
+ def status_sip
+ require 'freeswitch_event'
+ result = FreeswitchAPI.api_result(FreeswitchAPI.api('sofia', 'xmlstatus', 'gateway', "gateway#{self.id}"))
+ if result =~ /^\<\?xml/
+ data = Hash.from_xml(result)
+ if data
+ return data.fetch('gateway', nil)
+ end
+ end
+ return nil
+ end
+
def downcase_technology
self.technology = self.technology.downcase if !self.technology.blank?
end
diff --git a/app/models/gateway_setting.rb b/app/models/gateway_setting.rb
index 381dde5..b412bc6 100644
--- a/app/models/gateway_setting.rb
+++ b/app/models/gateway_setting.rb
@@ -5,11 +5,14 @@ class GatewaySetting < ActiveRecord::Base
'domain' => 'String',
'username' => 'String',
'password' => 'String',
- 'contact' => 'String',
'register' => 'Boolean',
'auth_source' => 'String',
'auth_pattern' => 'String',
+ 'inbound_username' => 'String',
+ 'inbound_password' => 'String',
'number_source' => 'String',
+ 'contact' => 'String',
+ 'dial_string' => 'String',
'profile' => 'String',
},
'xmpp' => {
diff --git a/app/models/hunt_group.rb b/app/models/hunt_group.rb
index 7338606..93279ae 100644
--- a/app/models/hunt_group.rb
+++ b/app/models/hunt_group.rb
@@ -2,7 +2,8 @@ class HuntGroup < ActiveRecord::Base
attr_accessible :name, :strategy, :seconds_between_jumps, :phone_numbers_attributes
belongs_to :tenant, :touch => true
- has_many :call_forwards, :as => :destinationable, :dependent => :destroy
+ has_many :destrination_call_forwards, :as => :destinationable, :dependent => :destroy
+ has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy
validates_uniqueness_of :name, :scope => :tenant_id,
:allow_nil => true, :allow_blank => true
diff --git a/app/models/intruder.rb b/app/models/intruder.rb
index 9a1c39a..9c01634 100644
--- a/app/models/intruder.rb
+++ b/app/models/intruder.rb
@@ -50,6 +50,27 @@ class Intruder < ActiveRecord::Base
}
end
+ def perimeter_db_rescan
+ Intruder.perimeter_control(:db_rescan, :key => self.key)
+ end
+
+ def self.perimeter_db_rescan(key=nil)
+ Intruder.perimeter_control(:db_rescan, :key => key)
+ end
+
+ def self.perimeter_control(action, attributes={})
+ require 'freeswitch_event'
+ event = FreeswitchEvent.new('CUSTOM')
+ event.add_header('Event-Subclass', 'perimeter::control')
+ event.add_header('action', action)
+ attributes.each do |name, value|
+ if !name.blank? && value then
+ event.add_header(name, value)
+ end
+ end
+ return event.fire()
+ end
+
private
def set_key_if_empty
if self.key.blank?
@@ -98,6 +119,7 @@ class Intruder < ActiveRecord::Base
write_firewall_list
restart_firewall
end
+ self.perimeter_db_rescan
end
end
@@ -108,6 +130,7 @@ class Intruder < ActiveRecord::Base
restart_firewall
end
end
+ self.perimeter_db_rescan
end
def check_if_delete_relevant
@@ -117,5 +140,6 @@ class Intruder < ActiveRecord::Base
restart_firewall
end
end
+ self.perimeter_db_rescan
end
end
diff --git a/app/models/ringtone.rb b/app/models/ringtone.rb
index 45ecd93..2b08c9f 100644
--- a/app/models/ringtone.rb
+++ b/app/models/ringtone.rb
@@ -24,6 +24,6 @@ class Ringtone < ActiveRecord::Base
belongs_to :ringtoneable, :polymorphic => true
def to_s
- self.bellcore_id.to_s
+ CORE_RINGTONES_AVAILABLE.index(self.bellcore_id)
end
end
diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb
index cdb609d..0c923be 100644
--- a/app/models/sip_account.rb
+++ b/app/models/sip_account.rb
@@ -41,6 +41,9 @@ class SipAccount < ActiveRecord::Base
has_many :call_legs, :class_name => 'Call'
has_many :b_call_legs, :class_name => 'Call', :foreign_key => 'b_sip_account_id'
+ has_many :acd_agents, :as => :destination, :dependent => :destroy
+ has_many :switchboard_entries, :dependent => :destroy
+
# Delegations:
#
delegate :host, :to => :sip_domain, :allow_nil => true
@@ -160,12 +163,16 @@ class SipAccount < ActiveRecord::Base
);
end
-
- def target_sip_accounts_by_permission(permission)
+ def target_group_ids_by_permission(permission)
target_groups = Group.union(self.groups.collect{|g| g.permission_targets(permission)})
target_groups = target_groups + Group.union(self.sip_accountable.groups.collect{|g| g.permission_targets(permission)})
+
+ return target_groups
+ end
+
+ def target_sip_accounts_by_permission(permission)
sip_accounts = []
- GroupMembership.where(:group_id => target_groups).each do |group_membership|
+ GroupMembership.where(:group_id => target_group_ids_by_permission(permission)).each do |group_membership|
if group_membership.item.class == User || group_membership.item.class == Tenant
sip_accounts = sip_accounts + group_membership.item.sip_accounts
elsif group_membership.item.class == SipAccount
@@ -178,6 +185,38 @@ class SipAccount < ActiveRecord::Base
return sip_accounts
end
+ def status
+ states = Array.new
+
+ self.call_legs.each do |call_leg|
+ states << {
+ :status => call_leg.b_callstate || call_leg.callstate,
+ :status_channel => call_leg.callstate,
+ :caller => true,
+ :endpoint_name => call_leg.callee_name,
+ :endpoint_number => call_leg.destination,
+ :endpoint_sip_account_id => call_leg.b_sip_account_id,
+ :start_stamp => call_leg.start_stamp,
+ :secure => call_leg.secure,
+ }
+ end
+
+ self.b_call_legs.each do |call_leg|
+ call_status =
+ states << {
+ :status => call_leg.b_callstate,
+ :status_channel => call_leg.b_callstate,
+ :caller => false,
+ :endpoint_name => call_leg.caller_id_name,
+ :endpoint_number => call_leg.caller_id_number,
+ :endpoint_sip_account_id => call_leg.sip_account_id,
+ :start_stamp => call_leg.start_stamp,
+ :secure => call_leg.b_secure,
+ }
+ end
+
+ return states
+ end
private
diff --git a/app/models/softkey.rb b/app/models/softkey.rb
index 6063017..27527f9 100644
--- a/app/models/softkey.rb
+++ b/app/models/softkey.rb
@@ -1,17 +1,17 @@
class Softkey < ActiveRecord::Base
- attr_accessible :softkey_function_id, :number, :label, :uuid, :softkeyable_type, :softkeyable_id
+ attr_accessible :softkey_function_id, :number, :label, :uuid, :softkeyable_type, :softkeyable_id, :call_forward, :blf
belongs_to :sip_account
belongs_to :softkey_function
belongs_to :softkeyable, :polymorphic => true
- validates_presence_of :softkeyable_id, :if => Proc.new{ |softkey| self.softkey_function_id != nil &&
- self.softkey_function_id == SoftkeyFunction.find_by_name('call_forwarding').try(:id) }
-
# These functions need a number to act.
#
validates_presence_of :number, :if => Proc.new{ |softkey| self.softkey_function_id != nil &&
- ['blf','speed_dial','dtmf','conference'].include?(softkey.softkey_function.name) }
+ ['blf', 'speed_dial','dtmf','conference'].include?(softkey.softkey_function.name) }
+
+ validates_presence_of :softkeyable_id, :if => Proc.new{ |softkey| self.softkey_function_id != nil &&
+ ['call_forwarding'].include?(softkey.softkey_function.name) }
validates_presence_of :uuid
validates_uniqueness_of :uuid
@@ -28,7 +28,6 @@ class Softkey < ActiveRecord::Base
call_forwards = call_forwards + phone_number.call_forwards
end
-
phone_numbers_ids = self.sip_account.phone_number_ids
phone_numbers = PhoneNumber.where(:id => phone_numbers_ids).pluck(:number)
@@ -43,7 +42,16 @@ class Softkey < ActiveRecord::Base
end
def possible_blf_sip_accounts
- self.sip_account.target_sip_accounts_by_permission('presence')
+ self.sip_account.target_sip_accounts_by_permission(:presence)
+ end
+
+ def possible_pickup_groups
+ Group.where(:id => self.sip_account.target_group_ids_by_permission(:presence))
+ end
+
+ def possible_blf
+ blf = possible_pickup_groups.collect{ |g| ["#{g.class.name}: #{g.to_s}", "#{g.id}:#{g.class.name}"] }
+ blf + possible_blf_sip_accounts.collect{ |g| ["#{g.class.name}: #{g.to_s}", "#{g.id}:#{g.class.name}"] }
end
def to_s
@@ -73,6 +81,7 @@ class Softkey < ActiveRecord::Base
return self.position.to_i < Softkey.where(:sip_account_id => self.sip_account_id ).order(:position).last.position.to_i
end
+
private
# Make sure that no number is set when there is no need for one.
# And make sure that there is no CallForward connected when not needed.
diff --git a/app/models/switchboard.rb b/app/models/switchboard.rb
new file mode 100644
index 0000000..74e2767
--- /dev/null
+++ b/app/models/switchboard.rb
@@ -0,0 +1,16 @@
+class Switchboard < ActiveRecord::Base
+ # https://github.com/rails/strong_parameters
+ include ActiveModel::ForbiddenAttributesProtection
+
+ validates :name,
+ :presence => true,
+ :uniqueness => {:scope => :user_id}
+
+ belongs_to :user, :touch => true
+ has_many :switchboard_entries, :dependent => :destroy
+ has_many :sip_accounts, :through => :switchboard_entries
+
+ def to_s
+ self.name.to_s
+ end
+end
diff --git a/app/models/switchboard_entry.rb b/app/models/switchboard_entry.rb
new file mode 100644
index 0000000..76d002f
--- /dev/null
+++ b/app/models/switchboard_entry.rb
@@ -0,0 +1,31 @@
+class SwitchboardEntry < ActiveRecord::Base
+ # https://github.com/rails/strong_parameters
+ include ActiveModel::ForbiddenAttributesProtection
+
+ belongs_to :switchboard, :touch => true
+ belongs_to :sip_account, :touch => true
+
+ validates :switchboard,
+ :presence => true
+
+ validates :sip_account,
+ :presence => true
+
+ validates :name,
+ :length => { :maximum => 10 },
+ :uniqueness => {:scope => :switchboard_id},
+ :allow_blank => true,
+ :allow_nil => true
+
+ acts_as_list :scope => [ :switchboard_id ]
+
+ default_scope order(:position)
+
+ def to_s
+ if self.name.blank? && !self.sip_account.to_s.blank?
+ self.sip_account.to_s
+ else
+ self.name.to_s
+ end
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 913d75f..b74fc06 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -74,8 +74,6 @@ class User < ActiveRecord::Base
has_many :fax_accounts, :as => :fax_accountable, :dependent => :destroy
- has_many :system_messages, :dependent => :destroy
-
has_many :auto_destroy_access_authorization_phone_numbers, :class_name => 'PhoneNumber', :foreign_key => 'access_authorization_user_id', :dependent => :destroy
belongs_to :current_tenant, :class_name => 'Tenant'
@@ -94,6 +92,8 @@ class User < ActiveRecord::Base
has_many :group_memberships, :as => :item, :dependent => :destroy, :uniq => true
has_many :groups, :through => :group_memberships
+ has_many :switchboards, :dependent => :destroy
+
# Avatar like photo
mount_uploader :image, ImageUploader