diff options
Diffstat (limited to 'app/models')
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 |