summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorStefan Wintermeyer <stefan.wintermeyer@amooma.de>2013-06-20 19:06:19 +0200
committerStefan Wintermeyer <stefan.wintermeyer@amooma.de>2013-06-20 19:06:19 +0200
commiteb0e1cc5c26275ff3e5c341404e8bc558f8312b8 (patch)
tree71f449ccd6f15422717de3ac24f87d5e888ddd79 /app/models
parentdf6e17e48995f25e72509986f30700d778b179b6 (diff)
parent3b27a5d45b12f6bac65da2a8e17387bfda42a2f1 (diff)
Merge branch 'develop'
Diffstat (limited to 'app/models')
-rw-r--r--app/models/ability.rb5
-rw-r--r--app/models/backup_job.rb2
-rw-r--r--app/models/call.rb21
-rw-r--r--app/models/call_forward.rb32
-rw-r--r--app/models/call_history.rb19
-rw-r--r--app/models/call_route.rb66
-rw-r--r--app/models/fax_account.rb1
-rw-r--r--app/models/gateway.rb10
-rw-r--r--app/models/gateway_setting.rb4
-rw-r--r--app/models/gemeinschaft_setup.rb22
-rw-r--r--app/models/generic_file.rb62
-rw-r--r--app/models/geo_ip_country.rb16
-rw-r--r--app/models/group.rb8
-rw-r--r--app/models/group_permission.rb2
-rw-r--r--app/models/gs_parameter.rb37
-rw-r--r--app/models/intruder.rb4
-rw-r--r--app/models/pager_group.rb36
-rw-r--r--app/models/pager_group_destination.rb15
-rw-r--r--app/models/phone_book_entry.rb2
-rw-r--r--app/models/phone_number.rb41
-rw-r--r--app/models/sip_account.rb31
-rw-r--r--app/models/softkey.rb5
-rw-r--r--app/models/switchboard.rb32
-rw-r--r--app/models/switchboard_entry.rb35
-rw-r--r--app/models/tenant.rb12
-rw-r--r--app/models/user.rb4
-rw-r--r--app/models/voicemail_account.rb64
-rw-r--r--app/models/voicemail_message.rb42
-rw-r--r--app/models/voicemail_setting.rb71
29 files changed, 609 insertions, 92 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 2dd96b8..8718dc4 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -181,8 +181,11 @@ class Ability
# Voicemail
#
+ can :read, VoicemailAccount
can :manage, VoicemailMessage
- can :manage, VoicemailSetting
+ can [:read, :edit, :update], VoicemailSetting
+
+ can :manage, GenericFile, :owner_type => 'User', :owner_id => user.id
# Switchboard
#
diff --git a/app/models/backup_job.rb b/app/models/backup_job.rb
index 9cb4f53..e2f2e6c 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} && nice -n 19 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 ionice -c2 -n7 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 a8a0d7f..2bbd08b 100644
--- a/app/models/call.rb
+++ b/app/models/call.rb
@@ -36,7 +36,7 @@ class Call < ActiveRecord::Base
def delete
require 'freeswitch_event'
- return FreeswitchAPI.execute('uuid_kill', self.uuid, true);
+ return FreeswitchAPI.execute('uuid_kill', self.uuid, true)
end
def transfer_blind(destination, call_leg=:aleg, auth_account=nil)
@@ -63,6 +63,25 @@ class Call < ActiveRecord::Base
return FreeswitchAPI.api_result(FreeswitchAPI.api('uuid_transfer', channel_uuid, destination))
end
+
+ def self.bridge(call_uuid1, call_uuid2, hangup_uuids=[])
+ if call_uuid1.blank? || call_uuid2.blank?
+ return nil
+ end
+
+ require 'freeswitch_event'
+ result = FreeswitchAPI.api_result(FreeswitchAPI.api('uuid_bridge', call_uuid1, call_uuid2))
+
+ if result
+ hangup_uuids.each do |kill_uuid|
+ FreeswitchAPI.execute('uuid_kill', kill_uuid, true)
+ end
+ end
+
+ return result
+ end
+
+
def get_variable_from_uuid(channel_uuid, variable_name)
if channel_uuid.blank?
return nil
diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb
index 195ac36..a4bfbb5 100644
--- a/app/models/call_forward.rb
+++ b/app/models/call_forward.rb
@@ -2,7 +2,7 @@ class CallForward < ActiveRecord::Base
attr_accessor :to_voicemail, :hunt_group_id
- attr_accessible :phone_number_id, :call_forward_case_id, :timeout,
+ attr_accessible :call_forward_case_id, :timeout,
:destination, :source, :depth, :active, :to_voicemail,
:hunt_group_id,
:call_forwardable_type, :call_forwardable_id,
@@ -56,7 +56,8 @@ class CallForward < ActiveRecord::Base
end
}
- before_save :split_and_format_destination_numbers
+ before_validation :resolve_prerouting
+
after_save :set_presence
after_save :deactivate_concurring_entries, :if => Proc.new { |cf| cf.active == true }
before_destroy :deactivate_connected_softkeys
@@ -71,7 +72,7 @@ class CallForward < ActiveRecord::Base
else
destinationable_type = " #{self.destinationable_type}"
end
- if self.destinationable
+ if Module.constants.include?(destinationable_type.to_sym) && self.destinationable
destination = "#{self.destinationable}#{destinationable_type}"
else
destination = "#{self.destination}#{destinationable_type}"
@@ -102,19 +103,6 @@ class CallForward < ActiveRecord::Base
end
private
- def split_and_format_destination_numbers
- if !self.destination.blank?
- destinations = self.destination.gsub(/[^+0-9\,]/,'').gsub(/[\,]+/,',').split(/\,/).delete_if{|x| x.blank?}
- self.destination = nil
- if destinations.count > 0
- destinations.each do |single_destination|
- self.destination = self.destination.to_s + ", #{PhoneNumber.parse_and_format(single_destination)}"
- end
- end
- self.destination = self.destination.to_s.gsub(/[^+0-9\,]/,'').gsub(/[\,]+/,',').split(/\,/).sort.delete_if{|x| x.blank?}.join(', ')
- end
- end
-
def set_presence
state = 'terminated'
@@ -149,6 +137,18 @@ class CallForward < ActiveRecord::Base
end
end
+ def resolve_prerouting
+ if self.destinationable_type == 'PhoneNumber' && GsParameter.get('CALLFORWARD_DESTINATION_RESOLVE') != false
+ if self.call_forwardable.class == PhoneNumber
+ prerouting = PhoneNumber.resolve_prerouting(self.destination, self.call_forwardable.phone_numberable)
+ else
+ prerouting = PhoneNumber.resolve_prerouting(self.destination, self.call_forwardable)
+ end
+ if prerouting && !prerouting['destination_number'].blank? && prerouting['type'] == 'phonenumber'
+ self.destination = prerouting['destination_number']
+ end
+ end
+ end
def send_presence_event(state, call_forwarding_service = nil)
dialplan_function = "cftg-#{self.id}"
diff --git a/app/models/call_history.rb b/app/models/call_history.rb
index 81342bd..8ccf4e3 100644
--- a/app/models/call_history.rb
+++ b/app/models/call_history.rb
@@ -133,19 +133,14 @@ class CallHistory < ActiveRecord::Base
end
- def voicemail_message?
- begin
- return self.call_historyable.voicemail_messages.where(:forwarded_by => self.caller_channel_uuid).any?
- rescue
- return nil
- end
- end
-
def voicemail_message
- begin
- return self.call_historyable.voicemail_messages.where(:forwarded_by => self.caller_channel_uuid).first
- rescue
- return nil
+ if self.callee_account_type.downcase == 'voicemailaccount'
+ voicemail_account = VoicemailAccount.where(:id => self.callee_account_id).first
+ if voicemail_account
+ return voicemail_account.voicemail_messages.where(:forwarded_by => self.caller_channel_uuid).first
+ else
+ return nil
+ end
end
end
diff --git a/app/models/call_route.rb b/app/models/call_route.rb
index 590d49b..7b98e5d 100644
--- a/app/models/call_route.rb
+++ b/app/models/call_route.rb
@@ -15,6 +15,8 @@ class CallRoute < ActiveRecord::Base
acts_as_list :scope => '`routing_table` = \'#{routing_table}\''
+ after_save :create_elements
+
def to_s
name.to_s
end
@@ -253,6 +255,47 @@ class CallRoute < ActiveRecord::Base
end
end
+ def xml
+ @xml
+ end
+
+ def xml=(xml_string)
+ @xml = xml_string
+ if xml_string.blank?
+ return
+ end
+
+ begin
+ route_hash = Hash.from_xml(xml_string)
+ rescue Exception => e
+ errors.add(:xml, e.message)
+ return
+ end
+
+ if route_hash['call_route'].class == Hash
+ call_route = route_hash['call_route']
+ self.routing_table = call_route['routing_table'].downcase
+ self.name = call_route['name'].downcase
+ self.position = call_route['position']
+ self.endpoint_type = call_route['endpoint_type']
+ endpoint_from_type_name(call_route['endpoint_type'], call_route['endpoint'])
+
+ if route_hash['call_route']['route_elements'] && route_hash['call_route']['route_elements']['route_element']
+ if route_hash['call_route']['route_elements']['route_element'].class == Hash
+ @elements_array = [route_hash['call_route']['route_elements']['route_element']]
+ else
+ @elements_array = route_hash['call_route']['route_elements']['route_element']
+ end
+ end
+ elsif route_hash['route_elements'].class == Hash && route_hash['route_elements']['route_element']
+ if route_hash['route_elements']['route_element'].class == Hash
+ @elements_array = [route_hash['route_elements']['route_element']]
+ else
+ @elements_array = route_hash['route_elements']['route_element']
+ end
+ end
+
+ end
def self.test_route(table, caller)
arguments = ["'#{table}' table"]
@@ -269,4 +312,27 @@ class CallRoute < ActiveRecord::Base
return JSON.parse(result)
end
+ private
+ def endpoint_from_type_name(endpoint_type, endpoint_name)
+ endpoint_type = endpoint_type.to_s.downcase
+ if endpoint_type == 'phonenumber'
+ self.endpoint_type = 'PhoneNumber'
+ self.endpoint_id = nil
+ elsif endpoint_type == 'gateway'
+ gateway = Gateway.where(:name => endpoint_name).first
+ if gateway
+ self.endpoint_type ='Gateway'
+ self.endpoint_id = gateway.id
+ end
+ end
+ end
+
+ def create_elements
+ if @elements_array && @elements_array.any?
+ @elements_array.each do |element_hash|
+ element = self.route_elements.create(element_hash)
+ end
+ end
+ end
+
end
diff --git a/app/models/fax_account.rb b/app/models/fax_account.rb
index 683447a..2677c5d 100644
--- a/app/models/fax_account.rb
+++ b/app/models/fax_account.rb
@@ -49,6 +49,7 @@ class FaxAccount < ActiveRecord::Base
tenant = case self.fax_accountable_type
when 'UserGroup' ; fax_accountable.tenant
when 'User' ; fax_accountable.current_tenant || fax_accountable.tenants.last
+ when 'Tenant' ; fax_accountable
else nil
end
self.tenant_id = tenant.id if tenant != nil
diff --git a/app/models/gateway.rb b/app/models/gateway.rb
index bf391fb..01b29b2 100644
--- a/app/models/gateway.rb
+++ b/app/models/gateway.rb
@@ -19,6 +19,8 @@ class Gateway < ActiveRecord::Base
after_initialize :set_defaults
before_validation :downcase_technology
+ after_create :create_default_settings
+
def to_s
name
end
@@ -65,4 +67,12 @@ class Gateway < ActiveRecord::Base
end
end
+ def create_default_settings
+ if self.technology == 'sip' then
+ GsParameter.where(:entity => 'sip_gateways', :section => 'settings').each do |default_setting|
+ self.gateway_settings.create(:name => default_setting.name, :value => default_setting.value, :class_type => default_setting.class_type, :description => default_setting.description)
+ end
+ end
+ end
+
end
diff --git a/app/models/gateway_setting.rb b/app/models/gateway_setting.rb
index b412bc6..e96bb52 100644
--- a/app/models/gateway_setting.rb
+++ b/app/models/gateway_setting.rb
@@ -14,6 +14,10 @@ class GatewaySetting < ActiveRecord::Base
'contact' => 'String',
'dial_string' => 'String',
'profile' => 'String',
+ 'from' => 'String',
+ 'from_clir' => 'String',
+ 'asserted_identity' => 'String',
+ 'asserted_identity_clir' => 'String',
},
'xmpp' => {
'server' => 'String',
diff --git a/app/models/gemeinschaft_setup.rb b/app/models/gemeinschaft_setup.rb
index 4b4dd37..ee8e981 100644
--- a/app/models/gemeinschaft_setup.rb
+++ b/app/models/gemeinschaft_setup.rb
@@ -20,6 +20,28 @@ class GemeinschaftSetup < ActiveRecord::Base
before_validation :format_default_area_code
+ def detect_attacks
+ if self[:detect_attacks] == nil
+ return true
+ end
+ return self[:detect_attacks]
+ end
+
+ def detect_attacks=(value)
+ self[:detect_attacks] = value
+ end
+
+ def report_attacks
+ if self[:report_attacks] == nil
+ return true
+ end
+ return self[:report_attacks]
+ end
+
+ def report_attacks=(value)
+ self[:report_attacks] = value
+ end
+
private
def expire_cache
ActionController::Base.expire_page(Rails.application.routes.url_helpers.new_gemeinschaft_setup_path)
diff --git a/app/models/generic_file.rb b/app/models/generic_file.rb
new file mode 100644
index 0000000..0e4dce5
--- /dev/null
+++ b/app/models/generic_file.rb
@@ -0,0 +1,62 @@
+class GenericFile < ActiveRecord::Base
+ FILE_TYPES = %w(pdf ps jpg gif png tif wav mp3)
+ CATEGORIES = %w(file document image greeting recording)
+
+ attr_accessible :name, :file, :file_type, :category, :owner_id, :owner_type
+
+ mount_uploader :file, GenericFileUploader
+
+ belongs_to :owner, :polymorphic => true
+
+ validates :name,
+ :presence => true,
+ :uniqueness => {:scope => [:owner_id, :owner_type]}
+
+ validates :file,
+ :presence => true
+
+ before_save :determine_file_type
+
+ def to_s
+ self.name
+ end
+
+ def store_dir
+ "/var/opt/gemeinschaft/generic_files/#{self.id.to_i}"
+ end
+
+ def mime_type
+ return GenericFile.mime_type(self.file.to_s)
+ end
+
+ def self.mime_type(file_name)
+ mime_type = `file -b --mime-type "#{file_name}"`.strip
+ if mime_type.blank?
+ mime_type = MIME::Types.type_for(file_name).first.to_s
+ end
+
+ return mime_type
+ end
+
+ def file_size
+ if self.file
+ return File.size(self.file.to_s)
+ else
+ return 0
+ end
+ end
+
+ def file_extension
+ mime_type = Mime::LOOKUP[self.file_type]
+ if mime_type.class == Mime::Type
+ return mime_type.symbol
+ end
+ end
+
+ private
+ def determine_file_type
+ if self.file_changed?
+ self.file_type = self.mime_type
+ end
+ end
+end
diff --git a/app/models/geo_ip_country.rb b/app/models/geo_ip_country.rb
new file mode 100644
index 0000000..add95d3
--- /dev/null
+++ b/app/models/geo_ip_country.rb
@@ -0,0 +1,16 @@
+class GeoIpCountry < ActiveRecord::Base
+ attr_accessible :country_code, :country_id, :country_name, :from, :n_from, :n_to, :to
+
+ def self.ip_to_i(ip_address)
+ octets = ip_address.split('.')
+ return (octets[0].to_i * 2**24) + (octets[1].to_i * 2**16) + (octets[2].to_i * 2**8) + octets[3].to_i
+ end
+
+ def self.find_by_ip(ip_address)
+ GeoIpCountry.where(GeoIpCountry.ip_to_i(ip_address).to_s + ' BETWEEN n_from AND n_to').first
+ end
+
+ def to_s
+ self.country_name
+ end
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 6c65f70..849fa71 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -29,4 +29,12 @@ class Group < ActiveRecord::Base
return group_ids.uniq
end
+
+ def self.target_group_ids_by_permission(permission, *group_sets)
+ target_groups = []
+ group_sets.each do |groups|
+ target_groups = target_groups + Group.union(groups.collect{|g| g.permission_targets(permission)})
+ end
+ return target_groups.uniq
+ end
end
diff --git a/app/models/group_permission.rb b/app/models/group_permission.rb
index c859f52..d9c8011 100644
--- a/app/models/group_permission.rb
+++ b/app/models/group_permission.rb
@@ -1,7 +1,7 @@
class GroupPermission < ActiveRecord::Base
attr_accessible :group_id, :permission, :target_group_id
- PERMISSION_TYPES = ['pickup', 'presence']
+ PERMISSION_TYPES = ['pickup', 'presence', 'forward_to',]
belongs_to :group
belongs_to :target_group, :class_name => "Group"
diff --git a/app/models/gs_parameter.rb b/app/models/gs_parameter.rb
index cd4f47b..f301e95 100644
--- a/app/models/gs_parameter.rb
+++ b/app/models/gs_parameter.rb
@@ -17,22 +17,37 @@ class GsParameter < ActiveRecord::Base
else
item = GsParameter.where(:name => wanted_variable).first
end
- if item.nil? || item.class_type == 'Nil'
- return nil
- else
- return item.value.to_i if item.class_type == 'Integer'
- return item.value.to_s if item.class_type == 'String'
- if item.class_type == 'Boolean'
- return true if item.value == 'true'
- return false if item.value == 'false'
- end
- return YAML.load(item.value) if item.class_type == 'YAML'
- end
+ return GsParameter.cast_variable(item)
else
nil
end
end
+ def self.get_list(entity, section)
+ items = {}
+ if GsParameter.table_exists?
+ GsParameter.where(:entity => entity, :section => section).each do |item|
+ items[item.name] = GsParameter.cast_variable(item)
+ end
+ end
+
+ return items
+ end
+
+ def self.cast_variable(item)
+ if item.nil? || item.class_type == 'Nil'
+ return nil
+ else
+ return item.value.to_i if item.class_type == 'Integer'
+ return item.value.to_s if item.class_type == 'String'
+ if item.class_type == 'Boolean'
+ return true if item.value == 'true'
+ return false if item.value == 'false'
+ end
+ return YAML.load(item.value) if item.class_type == 'YAML'
+ end
+ end
+
def to_s
name
end
diff --git a/app/models/intruder.rb b/app/models/intruder.rb
index 9c01634..c305bd3 100644
--- a/app/models/intruder.rb
+++ b/app/models/intruder.rb
@@ -25,6 +25,10 @@ class Intruder < ActiveRecord::Base
key
end
+ def country
+ GeoIpCountry.find_by_ip(self.contact_ip)
+ end
+
def whois(ip_address = self.contact_ip)
if ! ip_address.blank?
begin
diff --git a/app/models/pager_group.rb b/app/models/pager_group.rb
new file mode 100644
index 0000000..5c91ed8
--- /dev/null
+++ b/app/models/pager_group.rb
@@ -0,0 +1,36 @@
+class PagerGroup < ActiveRecord::Base
+ attr_accessible :sip_account_id, :callback_url
+ attr_writer :pager_group_destination_ids
+
+ has_many :pager_group_destinations, :dependent => :destroy
+ belongs_to :sip_account
+
+ validates_presence_of :sip_account_id
+
+ after_create :call
+ before_destroy :hangup_all
+
+ before_save :save_pager_group_destination_ids
+
+ def save_pager_group_destination_ids
+ if @pager_group_destination_ids
+ self.pager_group_destination_ids = @pager_group_destination_ids.split(/,/).map { |sip_account_id| self.pager_group_destinations.build(:sip_account_id => sip_account_id) }
+ end
+ end
+
+ def identifier
+ "pager#{self.id}"
+ end
+
+ def call
+ self.sip_account.call("f-pager-#{self.id}")
+ end
+
+ def hangup_all
+ require 'freeswitch_event'
+ return FreeswitchAPI.execute(
+ 'conference', "#{self.identifier} hup all",
+ true
+ );
+ end
+end
diff --git a/app/models/pager_group_destination.rb b/app/models/pager_group_destination.rb
new file mode 100644
index 0000000..98a1b32
--- /dev/null
+++ b/app/models/pager_group_destination.rb
@@ -0,0 +1,15 @@
+class PagerGroupDestination < ActiveRecord::Base
+ attr_accessible :pager_group_id, :sip_account_id
+
+ belongs_to :pager_group
+ belongs_to :sip_account
+
+ validates_presence_of :pager_group_id
+ validates_presence_of :sip_account_id
+
+ after_create :call
+
+ def call
+ self.sip_account.call("f-pager-#{self.pager_group_id}", '', "Pager #{self.id}")
+ end
+end
diff --git a/app/models/phone_book_entry.rb b/app/models/phone_book_entry.rb
index 96c8468..2a094f7 100644
--- a/app/models/phone_book_entry.rb
+++ b/app/models/phone_book_entry.rb
@@ -1,7 +1,7 @@
# encoding: UTF-8
class PhoneBookEntry < ActiveRecord::Base
- PHONE_NUMBER_NAMES = ['Phone', 'Office', 'Home', 'Mobile', 'Fax']
+ PHONE_NUMBER_NAMES = ['Phone', 'Office', 'Home', 'Mobile', 'Fax', 'Speeddial']
before_save :run_phonetic_algorithm
before_save :save_value_of_to_s
diff --git a/app/models/phone_number.rb b/app/models/phone_number.rb
index f6453ce..4f92731 100644
--- a/app/models/phone_number.rb
+++ b/app/models/phone_number.rb
@@ -16,7 +16,6 @@ class PhoneNumber < ActiveRecord::Base
validate :validate_inbound_uniqueness
before_save :save_value_of_to_s
- after_create :copy_existing_call_forwards_if_necessary
before_validation :'parse_and_split_number!'
validate :validate_number, :if => Proc.new { |phone_number| GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') && GsParameter.get('STRICT_DID_HANDLING') }
validate :check_if_number_is_available, :if => Proc.new { |phone_number| GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') && GsParameter.get('STRICT_DID_HANDLING') }
@@ -210,6 +209,10 @@ class PhoneNumber < ActiveRecord::Base
self.central_office_code = nil
self.extension = self.number.to_s.strip
else
+ prerouting = resolve_prerouting
+ if prerouting && !prerouting['destination_number'].blank? && prerouting['type'] == 'phonenumber'
+ self.number = prerouting['destination_number']
+ end
parsed_number = PhoneNumber.parse( self.number )
if parsed_number
self.country_code = parsed_number[:country_code]
@@ -223,6 +226,28 @@ class PhoneNumber < ActiveRecord::Base
end
end
end
+
+ def resolve_prerouting
+ return PhoneNumber.resolve_prerouting(self.number.strip, self.phone_numberable)
+ end
+
+ def self.resolve_prerouting(number, account = nil)
+ account = account || SipAccount.first
+
+ routes = CallRoute.test_route(:prerouting, {
+ 'caller.destination_number' => number,
+ 'caller.auth_account_type' => account.class.name,
+ 'caller.auth_account_id' => account.id,
+ 'caller.auth_account_uuid' => account.try(:uuid),
+ 'caller.account_type' => account.class.name,
+ 'caller.account_id' => account.id,
+ 'caller.account_uuid' => account.try(:uuid),
+ })
+
+ if routes
+ return routes['routes']['1']
+ end
+ end
# Find the (grand-)parent tenant of this phone number:
#
@@ -287,18 +312,4 @@ class PhoneNumber < ActiveRecord::Base
def save_value_of_to_s
self.value_of_to_s = self.to_s
end
-
- def copy_existing_call_forwards_if_necessary
- if self.phone_numberable.class == SipAccount && self.phone_numberable.callforward_rules_act_per_sip_account == true
- sip_account = SipAccount.find(self.phone_numberable)
- if sip_account.phone_numbers.where('id != ?', self.id).count > 0
- if sip_account.phone_numbers.where('id != ?', self.id).order(:created_at).first.call_forwards.count > 0
- sip_account.phone_numbers.where('id != ?', self.id).first.call_forwards.each do |call_forward|
- call_forward.set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account
- end
- end
- end
- end
- end
-
end
diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb
index 0c923be..668fbfe 100644
--- a/app/models/sip_account.rb
+++ b/app/models/sip_account.rb
@@ -6,7 +6,8 @@ class SipAccount < ActiveRecord::Base
attr_accessible :auth_name, :caller_name, :password, :voicemail_pin,
:tenant_id, :call_waiting, :clir, :clip_no_screening,
:clip, :description, :callforward_rules_act_per_sip_account,
- :hotdeskable, :gs_node_id, :language_code
+ :hotdeskable, :gs_node_id, :language_code, :voicemail_account_id
+
# Associations:
#
@@ -27,8 +28,6 @@ class SipAccount < ActiveRecord::Base
has_many :call_histories, :as => :call_historyable, :dependent => :destroy
- has_one :voicemail_setting, :class_name => "VoicemailSetting", :primary_key => 'auth_name', :foreign_key => 'username', :dependent => :destroy
-
belongs_to :gs_node
belongs_to :language, :foreign_key => 'language_code', :primary_key => 'code'
@@ -44,6 +43,11 @@ class SipAccount < ActiveRecord::Base
has_many :acd_agents, :as => :destination, :dependent => :destroy
has_many :switchboard_entries, :dependent => :destroy
+ has_many :voicemail_accounts, :as => :voicemail_accountable, :dependent => :destroy
+ belongs_to :voicemail_account
+
+ has_many :pager_groups, :dependent => :destroy
+
# Delegations:
#
delegate :host, :to => :sip_domain, :allow_nil => true
@@ -58,15 +62,11 @@ class SipAccount < ActiveRecord::Base
validate_sip_password :password
- validates_format_of :voicemail_pin, :with => /[0-9]+/,
- :allow_nil => true, :allow_blank => true
-
validates_uniqueness_of :auth_name, :scope => :sip_domain_id
# Before and after hooks:
#
before_save :save_value_of_to_s
- after_save :create_voicemail_setting, :if => :'voicemail_setting == nil'
before_validation :find_and_set_tenant_id
before_validation :set_sip_domain_id
before_validation :convert_umlauts_in_caller_name
@@ -154,11 +154,12 @@ class SipAccount < ActiveRecord::Base
return SipRegistration.where(:sip_user => self.auth_name).first
end
- def call( phone_number )
+ def call( phone_number, origin_cid_number = nil, origin_cid_name = 'Call' )
+ origin_cid_number = origin_cid_number || phone_number
require 'freeswitch_event'
return FreeswitchAPI.execute(
'originate',
- "{origination_uuid=#{UUID.new.generate},origination_caller_id_number='#{phone_number}',origination_caller_id_name='Call'}user/#{self.auth_name} #{phone_number}",
+ "{origination_uuid=#{UUID.new.generate},origination_caller_id_number='#{phone_number}',origination_caller_id_name='#{origin_cid_name}'}user/#{self.auth_name} #{phone_number}",
true
);
end
@@ -279,18 +280,6 @@ class SipAccount < ActiveRecord::Base
end
end
- def create_voicemail_setting
- voicemail_setting = VoicemailSetting.new()
- voicemail_setting.username = self.auth_name
- voicemail_setting.domain = self.sip_domain.try(:host)
- voicemail_setting.password = self.voicemail_pin
- voicemail_setting.notify = true
- voicemail_setting.attachment = true
- voicemail_setting.mark_read = true
- voicemail_setting.purge = false
- voicemail_setting.save
- end
-
def create_default_group_memberships
default_groups = Hash.new()
templates = GsParameter.get('SipAccount', 'group', 'default')
diff --git a/app/models/softkey.rb b/app/models/softkey.rb
index 27527f9..7e9b66d 100644
--- a/app/models/softkey.rb
+++ b/app/models/softkey.rb
@@ -35,10 +35,9 @@ class Softkey < ActiveRecord::Base
map{ |phone_number| phone_number.phone_numberable.hunt_group.id }.
uniq
- call_forwards = call_forwards + CallForward.where(:destinationable_type => 'HuntGroup', :destinationable_id => hunt_group_ids, :call_forwardable_type => 'PhoneNumber').
- where('call_forwardable_id NOT IN (?)', phone_numbers_ids)
+ call_forwards = call_forwards + CallForward.where(:destinationable_type => 'HuntGroup', :destinationable_id => hunt_group_ids, :call_forward_case_id => CallForwardCase.where(:value => 'assistant').first.try(:id))
- return call_forwards
+ return call_forwards.uniq
end
def possible_blf_sip_accounts
diff --git a/app/models/switchboard.rb b/app/models/switchboard.rb
index 74e2767..095f878 100644
--- a/app/models/switchboard.rb
+++ b/app/models/switchboard.rb
@@ -6,11 +6,43 @@ class Switchboard < ActiveRecord::Base
:presence => true,
:uniqueness => {:scope => :user_id}
+ validates :reload_interval,
+ :numericality => { :only_integer => true,
+ :greater_than => 249,
+ :allow_nil => true
+ }
+
+ validates :entry_width,
+ :numericality => { :only_integer => true,
+ :greater_than => 0,
+ :less_than => 5
+ }
+
+ validates :amount_of_displayed_phone_numbers,
+ :numericality => { :only_integer => true,
+ :greater_than_or_equal_to => 0,
+ :less_than => 20
+ }
+
belongs_to :user, :touch => true
has_many :switchboard_entries, :dependent => :destroy
has_many :sip_accounts, :through => :switchboard_entries
+ has_many :phone_numbers, :through => :sip_accounts
+
+ before_validation :convert_0_to_nil
def to_s
self.name.to_s
end
+
+ def active_calls
+ self.switchboard_entries.where(:switchable => true).map{|se| se.sip_account}.uniq.map{|sip_account| sip_account.calls}.flatten
+ end
+
+ private
+ def convert_0_to_nil
+ if self.reload_interval == 0
+ self.reload_interval = nil
+ end
+ end
end
diff --git a/app/models/switchboard_entry.rb b/app/models/switchboard_entry.rb
index 76d002f..44de7fd 100644
--- a/app/models/switchboard_entry.rb
+++ b/app/models/switchboard_entry.rb
@@ -5,6 +5,8 @@ class SwitchboardEntry < ActiveRecord::Base
belongs_to :switchboard, :touch => true
belongs_to :sip_account, :touch => true
+ has_many :phone_numbers, :through => :sip_account
+
validates :switchboard,
:presence => true
@@ -28,4 +30,37 @@ class SwitchboardEntry < ActiveRecord::Base
self.name.to_s
end
end
+
+ def avatar_src
+ if self.sip_account.sip_accountable.class == User
+ if self.sip_account.sip_accountable.image?
+ self.sip_account.sip_accountable.image_url(:profile)
+ else
+ if self.sip_account.sip_accountable.male?
+ '/assets/icons/user-male-16x.png'
+ else
+ '/assets/icons/user-female-16x.png'
+ end
+ end
+ else
+ nil
+ end
+ end
+
+ def callstate
+ if self.sip_account.call_legs.where(callstate: 'ACTIVE').any? || self.sip_account.b_call_legs.where(b_callstate: 'ACTIVE').any?
+ 'ACTIVE'
+ else
+ if self.sip_account.call_legs.where(callstate: 'EARLY').any?
+ 'EARLY'
+ else
+ if self.sip_account.call_legs.where(callstate: 'RINGING').any?
+ 'RINGING'
+ else
+ nil
+ end
+ end
+ end
+ end
+
end
diff --git a/app/models/tenant.rb b/app/models/tenant.rb
index ffa68a7..c70ec32 100644
--- a/app/models/tenant.rb
+++ b/app/models/tenant.rb
@@ -63,6 +63,10 @@ class Tenant < ActiveRecord::Base
has_many :group_memberships, :as => :item, :dependent => :destroy, :uniq => true
has_many :groups, :through => :group_memberships
+ has_many :voicemail_accounts, :as => :voicemail_accountable, :dependent => :destroy
+
+ has_many :generic_files, :as => :owner, :dependent => :destroy
+
# Validations:
#
validates_presence_of :name, :state, :country, :language
@@ -210,6 +214,14 @@ class Tenant < ActiveRecord::Base
self.array_of_available_internal_extensions + self.array_of_available_dids
end
+ def tenant_user_sip_accounts
+ SipAccount.where('(sip_accountable_type = "Tenant" AND sip_accountable_id = ?) OR (sip_accountable_type = "User" AND sip_accountable_id IN (?))', self.id, self.users.pluck(:id))
+ end
+
+ def tenant_user_phones
+ Phone.where('(phoneable_type = "Tenant" AND phoneable_id = ?) OR (phoneable_type = "User" AND phoneable_id IN (?))', self.id, self.users.pluck(:id))
+ end
+
private
# Create a public phone book for this tenant
diff --git a/app/models/user.rb b/app/models/user.rb
index b74fc06..5e97459 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -94,6 +94,10 @@ class User < ActiveRecord::Base
has_many :switchboards, :dependent => :destroy
+ has_many :voicemail_accounts, :as => :voicemail_accountable, :dependent => :destroy
+
+ has_many :generic_files, :as => :owner, :dependent => :destroy
+
# Avatar like photo
mount_uploader :image, ImageUploader
diff --git a/app/models/voicemail_account.rb b/app/models/voicemail_account.rb
new file mode 100644
index 0000000..8ec181f
--- /dev/null
+++ b/app/models/voicemail_account.rb
@@ -0,0 +1,64 @@
+class VoicemailAccount < ActiveRecord::Base
+ attr_accessible :uuid, :name, :active, :gs_node_id, :voicemail_accountable_type, :voicemail_accountable_id
+
+ belongs_to :voicemail_accountable, :polymorphic => true
+ has_many :voicemail_settings
+ has_many :voicemail_messages, :foreign_key => 'username', :primary_key => 'name'
+
+ validates :name,
+ :presence => true,
+ :uniqueness => true
+
+ validates :voicemail_accountable_id,
+ :presence => true
+
+ validates :voicemail_accountable_type,
+ :presence => true
+
+ def to_s
+ "#{voicemail_accountable.to_s}: #{name}"
+ end
+
+ def notify_to
+ send_notification = nil
+ if self.voicemail_settings.where(:name => 'notify', :value => true).first
+ send_notification = true
+ elsif self.voicemail_settings.where(:name => 'notify', :value => false).first
+ send_notification = false
+ end
+
+ if send_notification == nil
+ send_notification = GsParameter.get('notify', 'voicemail', 'settings')
+ end
+
+ if !send_notification
+ return send_notification
+ end
+
+ email = self.voicemail_settings.where(:name => 'email').first.try(:value)
+
+ if email.blank?
+ if self.voicemail_accountable.class == User
+ email = self.voicemail_accountable.email
+ end
+ end
+
+ return email
+ end
+
+
+ def notification_setting(name)
+ setting = nil
+ if self.voicemail_settings.where(:name => name, :value => true).first
+ setting = true
+ elsif self.voicemail_settings.where(:name => name, :value => false).first
+ setting = false
+ end
+
+ if setting == nil
+ setting = GsParameter.get(name, 'voicemail', 'settings')
+ end
+
+ return setting
+ end
+end
diff --git a/app/models/voicemail_message.rb b/app/models/voicemail_message.rb
index 91ba457..698aa50 100644
--- a/app/models/voicemail_message.rb
+++ b/app/models/voicemail_message.rb
@@ -2,7 +2,8 @@ class VoicemailMessage < ActiveRecord::Base
self.table_name = 'voicemail_msgs'
self.primary_key = 'uuid'
-# belongs_to :sip_account, :foreign_key => 'username', :primary_key => 'auth_name', :readonly => true
+ belongs_to :voicemail_account, :foreign_key => 'username', :primary_key => 'name', :readonly => true
+
# Prevent objects from being destroyed
def before_destroy
raise ActiveRecord::ReadOnlyRecord
@@ -49,4 +50,43 @@ class VoicemailMessage < ActiveRecord::Base
end
end
+ def phone_book_entry_by_number(number)
+ begin
+ voicemail_accountable = self.voicemail_account.voicemail_accountable
+ rescue
+ return nil
+ end
+
+ if ! voicemail_accountable
+ return nil
+ end
+
+ if voicemail_accountable.class == SipAccount
+ owner = voicemail_accountable.sip_accountable
+ else
+ owner = voicemail_accountable
+ end
+
+ if owner.class == User
+ phone_books = owner.phone_books.all
+ phone_books.concat(owner.current_tenant.phone_books.all)
+ elsif owner.class == Tenant
+ phone_books = owner.phone_books.all
+ end
+
+ if ! phone_books
+ return nil
+ end
+
+ phone_books.each do |phone_book|
+ phone_book_entry = phone_book.find_entry_by_number(number)
+ if phone_book_entry
+ return phone_book_entry
+ end
+ end
+
+ return nil
+
+ end
+
end
diff --git a/app/models/voicemail_setting.rb b/app/models/voicemail_setting.rb
index a8bb304..be3d749 100644
--- a/app/models/voicemail_setting.rb
+++ b/app/models/voicemail_setting.rb
@@ -1,12 +1,67 @@
-class VoicemailSetting < ActiveRecord::Base
- self.table_name = 'voicemail_prefs'
- self.primary_key = 'username'
+class VoicemailSetting < ActiveRecord::Base
+ CLASS_TYPES = ['String', 'Integer', 'Boolean']
+ VOICEMAIL_SETTINGS = {
+ 'pin' => { :type => 'String', :characters => /[^0-9]/, :html => { maxlength: 8 } },
+ 'notify' => { :type => 'Boolean', :input => :boolean },
+ 'attachment' => { :type => 'Boolean', :input => :boolean },
+ 'mark_read' => { :type => 'Boolean', :input => :boolean },
+ 'purge' => { :type => 'Boolean', :input => :boolean },
+ 'email' => { :type => 'String', },
+ 'record_length_max' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 100 } },
+ 'record_length_min' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 100 } },
+ 'records_max' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 100 } },
+ 'pin_length_max' => { :type => 'Integer', :input => :integer, :html => { min: 1, max: 10 } },
+ 'pin_length_min' => { :type => 'Integer', :input => :integer, :html => { min: 1, max: 8 } },
+ 'pin_timeout' => { :type => 'Integer', :input => :integer, :html => { min: 1, max: 10 } },
+ 'key_new_messages' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_saved_messages' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_config_menu' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_terminator' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_previous' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_next' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_delete' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_save' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'key_main_menu' => { :type => 'String', :characters => /[^0-9]\#\*/, :html => { maxlength: 1 } },
+ 'silence_lenght_abort' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 100 } },
+ 'silence_level' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 1000 } },
+ 'record_file_prefix' => { :type => 'String' },
+ 'record_file_suffix' => { :type => 'String' },
+ 'record_file_path' => { :type => 'String' },
+ 'record_repeat' => { :type => 'Integer', :input => :integer, :html => { min: 0, max: 10 } },
+ }
- attr_accessible :username, :domain, :name_path, :greeting_path, :password, :notify, :attachment, :mark_read, :purge, :sip_account
+ attr_accessible :voicemail_account_id, :name, :value, :class_type, :description
- has_one :sip_account, :foreign_key => 'auth_name'
+ belongs_to :voicemail_account
- validates_presence_of :username
- validates_presence_of :domain
- validates :username, :uniqueness => {:scope => :domain}
+ validates :name,
+ :presence => true,
+ :uniqueness => {:scope => :voicemail_account_id}
+
+ validates :class_type,
+ :presence => true,
+ :inclusion => { :in => CLASS_TYPES }
+
+ before_validation :set_class_type_and_value
+
+ def to_s
+ name
+ end
+
+ def set_class_type_and_value
+ seting_pref = VOICEMAIL_SETTINGS[self.name]
+ if seting_pref
+ self.class_type = seting_pref[:type]
+ case self.class_type
+ when 'String'
+ if seting_pref[:characters] && self.class_type == 'String'
+ self.value = self.value.to_s.gsub(seting_pref[:characters], '')
+ end
+ when 'Integer'
+ self.value = self.value.to_i
+ when 'Boolean'
+ self.value = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(self.value).to_s
+ end
+ end
+ end
end