diff options
Diffstat (limited to 'app/models')
27 files changed, 473 insertions, 56 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb index d9ec74a..b846af0 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -27,6 +27,10 @@ class Ability # cannot [:create, :destroy, :edit, :update], Tenant, :id => 1 + # Can't destroy any tenant + # + cannot :destroy, Tenant + cannot :manage, PhoneBook # Phonebooks and PhoneBookEntries @@ -70,9 +74,14 @@ class Ability # Dirty hack to disable PhoneNumberRange in the GUI # - if STRICT_INTERNAL_EXTENSION_HANDLING == false + if GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') == false cannot :manage, PhoneNumberRange end + + # GsParameter and GuiFunction can't be created or deleted via the GUI + # + cannot [:create, :destroy], GsParameter + cannot [:create, :destroy], GuiFunction else # Any user can do the following stuff. # diff --git a/app/models/access_authorization.rb b/app/models/access_authorization.rb index ef33115..878799a 100644 --- a/app/models/access_authorization.rb +++ b/app/models/access_authorization.rb @@ -18,7 +18,9 @@ class AccessAuthorization < ActiveRecord::Base :allow_nil => true, :allow_blank => true, :message => "must be numeric." - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + validates_length_of :pin, + :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), + :maximum => (GsParameter.get('MAXIMUM_PIN_LENGTH').nil? ? 10 : GsParameter.get('MAXIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy diff --git a/app/models/api/row.rb b/app/models/api/row.rb index ac35516..e82a3e2 100644 --- a/app/models/api/row.rb +++ b/app/models/api/row.rb @@ -28,7 +28,7 @@ class Api::Row < ActiveRecord::Base end def create_a_new_gemeinschaft_user - tenant = Tenant.find(DEFAULT_API_TENANT_ID) + tenant = Tenant.find(GsParameter.get('DEFAULT_API_TENANT_ID')) # Find or create the user # diff --git a/app/models/automatic_call_distributor.rb b/app/models/automatic_call_distributor.rb index cd887d5..5807757 100644 --- a/app/models/automatic_call_distributor.rb +++ b/app/models/automatic_call_distributor.rb @@ -1,7 +1,7 @@ class AutomaticCallDistributor < ActiveRecord::Base attr_accessible :uuid, :name, :strategy, :automatic_call_distributorable_type, :automatic_call_distributorable_id, :max_callers, :agent_timeout, :retry_timeout, :join, :leave, :gs_node_id, :announce_position, :announce_call_agents, :greeting, :goodbye, :music - belongs_to :automatic_call_distributorable, :polymorphic => true + belongs_to :automatic_call_distributorable, :polymorphic => true, :touch => true has_many :acd_agents, :dependent => :destroy has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy @@ -26,6 +26,6 @@ class AutomaticCallDistributor < ActiveRecord::Base self.announce_call_agents ||= 'ivr/ivr-stay_on_line_call_answered_momentarily.wav' self.greeting ||= 'ivr/ivr-thank_you_for_calling.wav' self.goodbye ||= 'ivr/ivr-thank_you_for_calling.wav' - self.music ||= 'local_stream://mohl' + self.music ||= 'local_stream://moh' end end diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb index 0018cfb..8a8d1df 100644 --- a/app/models/call_forward.rb +++ b/app/models/call_forward.rb @@ -28,7 +28,7 @@ class CallForward < ActiveRecord::Base validates_numericality_of :depth, :only_integer => true, :greater_than_or_equal_to => 1, - :less_than_or_equal_to => MAX_CALL_FORWARD_DEPTH + :less_than_or_equal_to => (GsParameter.get('MAX_CALL_FORWARD_DEPTH').nil? ? 0 : GsParameter.get('MAX_CALL_FORWARD_DEPTH')) before_validation { self.timeout = nil if self.call_forward_case_id != 3 diff --git a/app/models/call_route.rb b/app/models/call_route.rb new file mode 100644 index 0000000..28120c1 --- /dev/null +++ b/app/models/call_route.rb @@ -0,0 +1,241 @@ +class CallRoute < ActiveRecord::Base + # https://github.com/rails/strong_parameters + include ActiveModel::ForbiddenAttributesProtection + + ROUTING_TABLES = ['prerouting', 'outbound', 'inbound'] + + has_many :route_elements, :dependent => :destroy + + validates :name, + :presence => true + + validates :routing_table, + :presence => true, + :inclusion => { :in => ROUTING_TABLES } + + acts_as_list :scope => '`routing_table` = \'#{routing_table}\'' + + def to_s + name.to_s + end + + def move_up? + return self.position.to_i > CallRoute.where(:routing_table => self.routing_table ).order(:position).first.position.to_i + end + + def move_down? + return self.position.to_i < CallRoute.where(:routing_table => self.routing_table ).order(:position).last.position.to_i + end + + def self.factory_defaults_prerouting(country_code, national_prefix = '', international_prefix = '', trunk_access_code = '', area_code = '') + CallRoute.where(:routing_table => "prerouting").destroy_all + + CallRoute.create_prerouting_entry('international call', [ + { :pattern => '^'+trunk_access_code+international_prefix+'([1-9]%d+)$', :replacement => '+%1', }, + ], 'phonenumber') + + CallRoute.create_prerouting_entry('national call', [ + { :pattern => '^'+trunk_access_code+national_prefix+'([1-9]%d+)$', :replacement => '+'+country_code+'%1', }, + ], 'phonenumber') + + if !trunk_access_code.blank? && !area_code.blank? + CallRoute.create_prerouting_entry('local call', [ + { :pattern => '^'+trunk_access_code+'([1-9]%d+)$', :replacement => '+'+country_code+area_code+'%1', }, + ], 'phonenumber') + end + + CallRoute.create_prerouting_entry('log in', [ + { :pattern => '^%*0%*$', :replacement => 'f-li', }, + { :pattern => '^%*0%*(%+?%d+)#*$', :replacement => 'f-li-%1', }, + { :pattern => '^%*0%*(%+?%d+)%*(%d+)#*$', :replacement => 'f-li-%1-%2', }, + ]) + + CallRoute.create_prerouting_entry('log out', [ + { :pattern => '^#0#$', :replacement => 'f-lo', }, + ]) + + CallRoute.create_prerouting_entry('toggle ACD membership', [ + { :pattern => '^%*5%*(%+?%d+)#$', :replacement => 'f-acdmtg-0-%1', }, + ]) + + CallRoute.create_prerouting_entry('activate CLIP', [ + { :pattern => '^%*30#$', :replacement => 'f-clipon', }, + ]) + + CallRoute.create_prerouting_entry('deactivate CLIP', [ + { :pattern => '^#30#$', :replacement => 'f-clipoff', }, + ]) + + CallRoute.create_prerouting_entry('activate CLIR', [ + { :pattern => '^#31#$', :replacement => 'f-cliron', }, + ]) + + CallRoute.create_prerouting_entry('deactivate CLIR', [ + { :pattern => '^%*31#$', :replacement => 'f-cliroff', }, + ]) + + elements = [ + { :pattern => '^#31#(%+?[1-9]%d+)$', :replacement => 'f-dcliron-%1', }, + { :pattern => '^#31#'+trunk_access_code+international_prefix+'([1-9]%d+)$', :replacement => 'f-dcliron-+%1' }, + { :pattern => '^#31#'+trunk_access_code+national_prefix+'([1-9]%d+)$', :replacement => 'f-dcliron-+'+country_code+'%1' }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^#31#'+trunk_access_code+'([1-9]%d+)$', :replacement => 'f-dcliron-+'+country_code+area_code+'%1' } + end + + CallRoute.create_prerouting_entry('activate CLIR for call', elements) + + elements = [ + { :pattern => '^%*31#(%+?[1-9]%d+)$', :replacement => 'f-dcliroff-%1', }, + { :pattern => '^%*31#'+trunk_access_code+international_prefix+'([1-9]%d+)$', :replacement => 'f-dcliroff-+%1' }, + { :pattern => '^%*31#'+trunk_access_code+national_prefix+'([1-9]%d+)$', :replacement => 'f-dcliroff-+'+country_code+'%1' }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^%*31#'+trunk_access_code+'([1-9]%d+)$', :replacement => 'f-dcliroff-+'+country_code+area_code+'%1' } + end + + CallRoute.create_prerouting_entry('deactivate CLIR for call', elements) + + CallRoute.create_prerouting_entry('activate call waiting', [ + { :pattern => '^%*43#$', :replacement => 'f-cwaon', }, + ]) + + CallRoute.create_prerouting_entry('deactivate call waiting', [ + { :pattern => '^#43#$', :replacement => 'f-cwaoff', }, + ]) + + CallRoute.create_prerouting_entry('deactivate all call forwards', [ + { :pattern => '^#002#$', :replacement => 'f-cfoff', }, + ]) + + CallRoute.create_prerouting_entry('delete all call forwards', [ + { :pattern => '^##002#$', :replacement => 'f-cfdel', }, + ]) + + elements = [ + { :pattern => '^%*21#$', :replacement => 'f-cfu', }, + { :pattern => '^%*%*?21%*(%+?[1-9]%d+)#$', :replacement => 'f-cfu-%1', }, + { :pattern => '^%*%*?21%*'+trunk_access_code+international_prefix+'([1-9]%d+)#$', :replacement => 'f-cfu-+%1', }, + { :pattern => '^%*%*?21%*'+trunk_access_code+national_prefix+'([1-9]%d+)#$', :replacement => 'f-cfu-+'+country_code+'%1', }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^%*%*?21%*'+trunk_access_code+'([1-9]%d+)#$', :replacement => 'f-cfu-+'+country_code+area_code+'%1' } + end + + CallRoute.create_prerouting_entry('set unconditional call forwarding', elements) + + CallRoute.create_prerouting_entry('deactivate unconditional call forwarding', [ + { :pattern => '^#21#$', :replacement => 'f-cfuoff', }, + ]) + + CallRoute.create_prerouting_entry('delete unconditional call forwarding', [ + { :pattern => '^##21#$', :replacement => 'f-cfudel', }, + ]) + + elements = [ + { :pattern => '^%*61#$', :replacement => 'f-cfn', }, + { :pattern => '^%*%*?61%*'+trunk_access_code+international_prefix+'([1-9]%d+)#$', :replacement => 'f-cfn-+%1', }, + { :pattern => '^%*%*?61%*'+trunk_access_code+national_prefix+'([1-9]%d+)#$', :replacement => 'f-cfn-+'+country_code+'%1', }, + { :pattern => '^%*%*?61%*(%+?[1-9]%d+)#$', :replacement => 'f-cfn-%1', }, + { :pattern => '^%*%*?61%*'+trunk_access_code+international_prefix+'([1-9]%d+)%*(%d+)#$', :replacement => 'f-cfn-+%1-%2', }, + { :pattern => '^%*%*?61%*'+trunk_access_code+national_prefix+'([1-9]%d+)%*(%d+)#$', :replacement => 'f-cfn-+'+country_code+'%1-%2', }, + { :pattern => '^%*%*?61%*(%+?[1-9]%d+)%*(%d+)#$', :replacement => 'f-cfn-%1-%2', }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^%*%*?61%*'+trunk_access_code+'([1-9]%d+)#$', :replacement => 'f-cfn-+'+country_code+area_code+'%1' } + elements << { :pattern => '^%*%*?61%*'+trunk_access_code+'([1-9]%d+)%*(%d+)#$', :replacement => 'f-cfn-+'+country_code+area_code+'%1-%2' } + end + + CallRoute.create_prerouting_entry('call forward if not answered', elements) + + CallRoute.create_prerouting_entry('deactivate call forward if not answered', [ + { :pattern => '^#61#$', :replacement => 'f-cfnoff', }, + ]) + + CallRoute.create_prerouting_entry('delete call forward if not answered', [ + { :pattern => '^##61#$', :replacement => 'f-cfndel', }, + ]) + + elements = [ + { :pattern => '^%*62#$', :replacement => 'f-cfo', }, + { :pattern => '^%*%*?62%*(%+?[1-9]%d+)#$', :replacement => 'f-cfo-%1', }, + { :pattern => '^%*%*?62%*'+trunk_access_code+international_prefix+'([1-9]%d+)#$', :replacement => 'f-cfo-+%1', }, + { :pattern => '^%*%*?62%*'+trunk_access_code+national_prefix+'([1-9]%d+)#$', :replacement => 'f-cfo-+'+country_code+'%1', }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^%*%*?62%*'+trunk_access_code+'([1-9]%d+)#$', :replacement => 'f-cfo-+'+country_code+area_code+'%1' } + end + + CallRoute.create_prerouting_entry('call forward if offline', elements) + + CallRoute.create_prerouting_entry('deactivate call forward if offline', [ + { :pattern => '^#62#$', :replacement => 'f-cfooff', }, + ]) + + CallRoute.create_prerouting_entry('delete call forward if offline', [ + { :pattern => '^##62#$', :replacement => 'f-cfodel', }, + ]) + + elements = [ + { :pattern => '^%*67#$', :replacement => 'f-cfb', }, + { :pattern => '^%*%*?67%*(%+?[1-9]%d+)#$', :replacement => 'f-cfb-%1', }, + { :pattern => '^%*%*?67%*'+trunk_access_code+international_prefix+'([1-9]%d+)#$', :replacement => 'f-cfb-+%1', }, + { :pattern => '^%*%*?67%*'+trunk_access_code+national_prefix+'([1-9]%d+)#$', :replacement => 'f-cfb-+'+country_code+'%1', }, + ] + + if !trunk_access_code.blank? && !area_code.blank? + elements << { :pattern => '^%*%*?67%*'+trunk_access_code+'([1-9]%d+)#$', :replacement => 'f-cfb-+'+country_code+area_code+'%1' } + end + + CallRoute.create_prerouting_entry('call forward if busy', elements) + + CallRoute.create_prerouting_entry('deactivate call forward if busy', [ + { :pattern => '^#67#$', :replacement => 'f-cfboff', }, + ]) + + CallRoute.create_prerouting_entry('delete call forward if busy', [ + { :pattern => '^##67#$', :replacement => 'f-cfbdel', }, + ]) + + + CallRoute.create_prerouting_entry('redial', [ + { :pattern => '^%*66#$', :replacement => 'f-redial', }, + ]) + + CallRoute.create_prerouting_entry('check voicemail', [ + { :pattern => '^%*98$', :replacement => 'f-vmcheck', }, + { :pattern => '^%*98#$', :replacement => 'f-vmcheck', }, + { :pattern => '^%*98%*(%+?%d+)#$', :replacement => 'f-vmcheck-%1', }, + ]) + + CallRoute.create_prerouting_entry('acivate auto logout', [ + { :pattern => '^%*1337%*1%*1#$', :replacement => 'f-loaon', }, + ]) + + CallRoute.create_prerouting_entry('deacivate auto logout', [ + { :pattern => '^%*1337%*1%*0#$', :replacement => 'f-loaoff', }, + ]) + end + + def self.create_prerouting_entry(name, elements, endpoint_type = 'dialplanfunction') + call_route = CallRoute.create(:routing_table => 'prerouting', :name => name, :endpoint_type => endpoint_type) + + if !call_route.errors.any? then + elements.each do |element| + call_route.route_elements.create( + :var_in => 'destination_number', + :var_out => 'destination_number', + :pattern => element[:pattern], + :replacement => element[:replacement], + :action => 'match', + :mandatory => false + ) + end + end + end +end diff --git a/app/models/callthrough.rb b/app/models/callthrough.rb index c057fa6..ae461cf 100644 --- a/app/models/callthrough.rb +++ b/app/models/callthrough.rb @@ -5,7 +5,7 @@ class Callthrough < ActiveRecord::Base # Validations and Associations # - belongs_to :tenant + belongs_to :tenant, :touch => true validates_presence_of :tenant_id validates_presence_of :tenant diff --git a/app/models/conference.rb b/app/models/conference.rb index 8be9f21..8c5a752 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -3,7 +3,7 @@ class Conference < ActiveRecord::Base :open_for_anybody, :max_members, :announce_new_member_by_name, :announce_left_member_by_name - belongs_to :conferenceable, :polymorphic => true + belongs_to :conferenceable, :polymorphic => true, :touch => true has_many :conference_invitees, :dependent => :destroy has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy @@ -15,7 +15,7 @@ class Conference < ActiveRecord::Base validates_presence_of :max_members validates_numericality_of :max_members, :only_integer => true, :greater_than => 0, - :less_than => (MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE + 1), + :less_than => ((GsParameter.get('MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE').nil? ? 10 : GsParameter.get('MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE')) + 1), :allow_nil => false, :allow_blank => false @@ -25,7 +25,7 @@ class Conference < ActiveRecord::Base :greater_than => 0, :allow_nil => true, :allow_blank => true - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true diff --git a/app/models/conference_invitee.rb b/app/models/conference_invitee.rb index 7de20de..d6e3bac 100644 --- a/app/models/conference_invitee.rb +++ b/app/models/conference_invitee.rb @@ -13,7 +13,7 @@ class ConferenceInvitee < ActiveRecord::Base :greater_than => 0, :allow_nil => true, :allow_blank => true - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true diff --git a/app/models/fax_document.rb b/app/models/fax_document.rb index 67bdea9..080bdaa 100644 --- a/app/models/fax_document.rb +++ b/app/models/fax_document.rb @@ -54,7 +54,7 @@ class FaxDocument < ActiveRecord::Base private def render_thumbnails - directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/fax_thumbnails/#{self.id}" + directory = "/tmp/GS-#{GsParameter.get('GEMEINSCHAFT_VERSION')}/fax_thumbnails/#{self.id}" system('mkdir -p ' + directory) system("cd #{directory} && convert #{Rails.root.to_s}/public#{self.document.to_s}[0-100] -colorspace Gray PNG:'fax_page.png'") number_of_thumbnails = Dir["#{directory}/fax_page-*.png"].count @@ -70,7 +70,7 @@ class FaxDocument < ActiveRecord::Base def convert_pdf_to_tiff page_size_a4 = '595 842' page_size_command = "<< /Policies << /PageSize 3 >> /InputAttributes currentpagedevice /InputAttributes get dup { pop 1 index exch undef } forall dup 0 << /PageSize [ #{page_size_a4} ] >> put >> setpagedevice" - directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/faxes/#{self.id}" + directory = "/tmp/GS-#{GsParameter.get('GEMEINSCHAFT_VERSION')}/faxes/#{self.id}" system('mkdir -p ' + directory) tiff_file_name = File.basename(self.document.to_s.downcase, ".pdf") + '.tiff' system "cd #{directory} && gs -q -r#{self.fax_resolution.resolution_value} -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=\"#{tiff_file_name}\" -c \"#{page_size_command}\" -- \"#{Rails.root.to_s}/public#{self.document.to_s}\"" diff --git a/app/models/gateway.rb b/app/models/gateway.rb new file mode 100644 index 0000000..3e791a6 --- /dev/null +++ b/app/models/gateway.rb @@ -0,0 +1,35 @@ +class Gateway < ActiveRecord::Base + TECHNOLOGIES = ['sip'] + + attr_accessible :name, :technology, :inbound, :outbound, :description + + has_many :gateway_settings, :dependent => :destroy + has_many :gateway_parameters, :dependent => :destroy + + validates :name, + :presence => true, + :uniqueness => true + + validates :technology, + :presence => true, + :inclusion => { :in => TECHNOLOGIES } + + after_initialize :set_defaults + before_validation :downcase_technology + + def to_s + name + end + + private + def downcase_technology + self.technology = self.technology.downcase if !self.technology.blank? + end + + def set_defaults + if TECHNOLOGIES.count == 1 + self.technology = TECHNOLOGIES.first + end + end + +end diff --git a/app/models/gateway_parameter.rb b/app/models/gateway_parameter.rb new file mode 100644 index 0000000..a66af75 --- /dev/null +++ b/app/models/gateway_parameter.rb @@ -0,0 +1,19 @@ +class GatewayParameter < ActiveRecord::Base + CLASS_TYPES = ['String', 'Integer', 'Boolean'] + + attr_accessible :gateway_id, :name, :value, :class_type, :description + + belongs_to :gateway, :touch => true + + validates :name, + :presence => true, + :uniqueness => {:scope => :gateway_id} + + validates :class_type, + :presence => true, + :inclusion => { :in => CLASS_TYPES } + + def to_s + name + end +end diff --git a/app/models/gateway_setting.rb b/app/models/gateway_setting.rb new file mode 100644 index 0000000..c01f0a8 --- /dev/null +++ b/app/models/gateway_setting.rb @@ -0,0 +1,31 @@ +class GatewaySetting < ActiveRecord::Base + CLASS_TYPES = ['String', 'Integer', 'Boolean'] + GATEWAY_SETTINGS = { + 'sip' => { + 'domain' => 'String', + 'username' => 'String', + 'password' => 'String', + 'contact' => 'String', + 'register' => 'Boolean', + 'auth_source' => 'String', + 'auth_pattern' => 'String', + 'number_source' => 'String', + }, + } + + attr_accessible :gateway_id, :name, :value, :class_type, :description + + belongs_to :gateway + + validates :name, + :presence => true, + :uniqueness => {:scope => :gateway_id} + + validates :class_type, + :presence => true, + :inclusion => { :in => CLASS_TYPES } + + def to_s + name + end +end diff --git a/app/models/gemeinschaft_setup.rb b/app/models/gemeinschaft_setup.rb index b445b21..6056236 100644 --- a/app/models/gemeinschaft_setup.rb +++ b/app/models/gemeinschaft_setup.rb @@ -5,4 +5,25 @@ class GemeinschaftSetup < ActiveRecord::Base accepts_nested_attributes_for :sip_domain belongs_to :country belongs_to :language + + # Remove the cache which was created by the heater rake task. + # + after_create :expire_cache + + before_validation :format_default_area_code + + private + def expire_cache + ActionController::Base.expire_page(Rails.application.routes.url_helpers.new_gemeinschaft_setup_path) + end + + def format_default_area_code + if self.default_area_code.blank? + self.default_area_code = nil + else + if self.country != nil && !self.country.trunk_prefix.blank? + self.default_area_code.gsub(/^#{self.country.trunk_prefix}/,'') + end + end + end end diff --git a/app/models/gs_cluster_sync_log_entry.rb b/app/models/gs_cluster_sync_log_entry.rb index 063ff23..51e3b05 100644 --- a/app/models/gs_cluster_sync_log_entry.rb +++ b/app/models/gs_cluster_sync_log_entry.rb @@ -15,7 +15,7 @@ class GsClusterSyncLogEntry < ActiveRecord::Base after_create :apply_to_local_database def apply_to_local_database - if self.homebase_ip_address != HOMEBASE_IP_ADDRESS + if self.homebase_ip_address != GsParameter.get('HOMEBASE_IP_ADDRESS') if self.class_name.constantize.new.attribute_names.include?('is_native') case self.action when 'create' @@ -84,7 +84,7 @@ class GsClusterSyncLogEntry < ActiveRecord::Base end def populate_other_cluster_nodes - if self.homebase_ip_address == HOMEBASE_IP_ADDRESS && self.waiting_to_be_synced == true + if self.homebase_ip_address == GsParameter.get('HOMEBASE_IP_ADDRESS') && self.waiting_to_be_synced == true if GsNode.where(:push_updates_to => true).count > 0 GsNode.where(:push_updates_to => true).each do |gs_node| RemoteGsNode::GsClusterSyncLogEntry.site = gs_node.site diff --git a/app/models/gs_parameter.rb b/app/models/gs_parameter.rb new file mode 100644 index 0000000..fe2a845 --- /dev/null +++ b/app/models/gs_parameter.rb @@ -0,0 +1,35 @@ +class GsParameter < ActiveRecord::Base + # https://github.com/rails/strong_parameters + include ActiveModel::ForbiddenAttributesProtection + + validates :name, + :presence => true, + :uniqueness => { :scope => [ :entity, :section ] } + + validates :class_type, + :presence => true, + :inclusion => { :in => ['String', 'Integer', 'Boolean', 'YAML', 'Nil'] } + + def self.get(wanted_variable) + if GsParameter.table_exists? + item = GsParameter.where(:name => wanted_variable).first + 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 + else + nil + end + end + + def to_s + name + end +end diff --git a/app/models/hunt_group.rb b/app/models/hunt_group.rb index 276ae53..5011bf0 100644 --- a/app/models/hunt_group.rb +++ b/app/models/hunt_group.rb @@ -1,24 +1,24 @@ class HuntGroup < ActiveRecord::Base attr_accessible :name, :strategy, :seconds_between_jumps, :phone_numbers_attributes - belongs_to :tenant + belongs_to :tenant, :touch => true has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy validates_uniqueness_of :name, :scope => :tenant_id, :allow_nil => true, :allow_blank => true validates_presence_of :strategy - validates_inclusion_of :strategy, :in => HUNT_GROUP_STRATEGIES + validates_inclusion_of :strategy, :in => (GsParameter.get('HUNT_GROUP_STRATEGIES').nil? ? [] : GsParameter.get('HUNT_GROUP_STRATEGIES')) validates_presence_of :seconds_between_jumps, :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_numericality_of :seconds_between_jumps, :only_integer => true, - :greater_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.min, - :less_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.max, + :greater_than_or_equal_to => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? 2 : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').min), + :less_than_or_equal_to => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? 120 : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').max), :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_inclusion_of :seconds_between_jumps, - :in => VALID_SECONDS_BETWEEN_JUMPS_VALUES, + :in => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? [] : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES')), :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_inclusion_of :seconds_between_jumps, :in => [nil], diff --git a/app/models/phone.rb b/app/models/phone.rb index a606834..8b41b59 100644 --- a/app/models/phone.rb +++ b/app/models/phone.rb @@ -9,7 +9,7 @@ class Phone < ActiveRecord::Base # Associations # belongs_to :phone_model - belongs_to :phoneable, :polymorphic => true + belongs_to :phoneable, :polymorphic => true, :touch => true has_many :phone_sip_accounts, :dependent => :destroy, :uniq => true, :order => :position has_many :sip_accounts, :through => :phone_sip_accounts @@ -162,7 +162,6 @@ class Phone < ActiveRecord::Base if ! self.resync(true, sip_account_resync) errors.add(:resync, "Resync failed") - return false end return true @@ -201,6 +200,10 @@ class Phone < ActiveRecord::Base # Sanitize MAC address. # def sanitize_mac_address + if self.mac_address.split(/:/).count == 6 && self.mac_address.length < 17 + splitted_mac_address = self.mac_address.split(/:/) + self.mac_address = splitted_mac_address.map{|part| (part.size == 1 ? "0#{part}" : part)}.join('') + end self.mac_address = self.mac_address.to_s.upcase.gsub( /[^A-F0-9]/, '' ) end diff --git a/app/models/phone_book.rb b/app/models/phone_book.rb index 3603eae..21d30c0 100644 --- a/app/models/phone_book.rb +++ b/app/models/phone_book.rb @@ -1,7 +1,7 @@ class PhoneBook < ActiveRecord::Base attr_accessible :name, :description, :uuid - belongs_to :phone_bookable, :polymorphic => true + belongs_to :phone_bookable, :polymorphic => true, :touch => true has_many :phone_book_entries, :dependent => :destroy validates_presence_of :name diff --git a/app/models/phone_book_entry.rb b/app/models/phone_book_entry.rb index db2b44b..275c7b6 100644 --- a/app/models/phone_book_entry.rb +++ b/app/models/phone_book_entry.rb @@ -6,7 +6,7 @@ class PhoneBookEntry < ActiveRecord::Base attr_accessible :first_name, :middle_name, :last_name, :title, :nickname, :organization, :is_organization, :department, :job_title, :is_male, :birthday, :birth_name, :description, :homepage_personal, :homepage_organization, :twitter_account, :facebook_account, :google_plus_account, :xing_account, :linkedin_account, :mobileme_account, :image - belongs_to :phone_book + belongs_to :phone_book, :touch => true has_many :conference_invitees, :dependent => :destroy acts_as_list :scope => :phone_book diff --git a/app/models/phone_model.rb b/app/models/phone_model.rb index e00e0e3..ac4d4a3 100644 --- a/app/models/phone_model.rb +++ b/app/models/phone_model.rb @@ -3,7 +3,7 @@ class PhoneModel < ActiveRecord::Base # Associations # - belongs_to :manufacturer + belongs_to :manufacturer, :touch => true has_many :phones, :dependent => :destroy diff --git a/app/models/phone_number.rb b/app/models/phone_number.rb index 4c0cf46..d1e950f 100644 --- a/app/models/phone_number.rb +++ b/app/models/phone_number.rb @@ -18,8 +18,8 @@ class PhoneNumber < ActiveRecord::Base 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| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } - validate :check_if_number_is_available, :if => Proc.new { |phone_number| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } + 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') } acts_as_list :scope => [:phone_numberable_id, :phone_numberable_type] @@ -95,7 +95,7 @@ class PhoneNumber < ActiveRecord::Base else # Check if the number is an internal extension. if tenant - internal_extension_range = tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first + internal_extension_range = tenant.phone_number_ranges.where(:name => GsParameter.get('INTERNAL_EXTENSIONS')).first if internal_extension_range if internal_extension_range.phone_numbers.where(:number => number).length > 0 parts[:extension] = number @@ -192,8 +192,8 @@ class PhoneNumber < ActiveRecord::Base end def parse_and_split_number! - if self.phone_numberable_type == 'PhoneNumberRange' && self.phone_numberable.name == INTERNAL_EXTENSIONS - # The parent is the PhoneNumberRange INTERNAL_EXTENSIONS. Therefor it must be an extensions. + if self.phone_numberable_type == 'PhoneNumberRange' && self.phone_numberable.name == GsParameter.get('INTERNAL_EXTENSIONS') + # The parent is the PhoneNumberRange GsParameter.get('INTERNAL_EXTENSIONS'). Therefor it must be an extensions. # self.country_code = nil self.area_code = nil @@ -202,8 +202,8 @@ class PhoneNumber < ActiveRecord::Base self.extension = self.number.to_s.strip else if self.tenant && - self.tenant.phone_number_ranges.exists?(:name => INTERNAL_EXTENSIONS) && - self.tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first.phone_numbers.exists?(:number => self.number) + self.tenant.phone_number_ranges.exists?(:name => GsParameter.get('INTERNAL_EXTENSIONS')) && + self.tenant.phone_number_ranges.where(:name => GsParameter.get('INTERNAL_EXTENSIONS')).first.phone_numbers.exists?(:number => self.number) self.country_code = nil self.area_code = nil self.subscriber_number = nil @@ -263,7 +263,7 @@ class PhoneNumber < ActiveRecord::Base if self.phone_numberable_type != 'PhoneBookEntry' && self.tenant phone_number_ranges = self.tenant.phone_number_ranges.where( - :name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS] + :name => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')] ) if !phone_number_ranges.empty? if !PhoneNumber.where(:phone_numberable_type => 'PhoneNumberRange'). diff --git a/app/models/phone_number_range.rb b/app/models/phone_number_range.rb index 2fdd9b6..b666487 100644 --- a/app/models/phone_number_range.rb +++ b/app/models/phone_number_range.rb @@ -6,7 +6,7 @@ class PhoneNumberRange < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => [:phone_number_rangeable_id, :phone_number_rangeable_type] - validates_inclusion_of :name, :in => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS, SERVICE_NUMBERS] + validates_inclusion_of :name, :in => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS'), GsParameter.get('SERVICE_NUMBERS')] validates_presence_of :phone_number_rangeable_id validates_presence_of :phone_number_rangeable diff --git a/app/models/route_element.rb b/app/models/route_element.rb new file mode 100644 index 0000000..94f0f84 --- /dev/null +++ b/app/models/route_element.rb @@ -0,0 +1,26 @@ +class RouteElement < ActiveRecord::Base + ELEMENT_ACTIONS = ['none', 'match', 'not_match', 'set'] + + attr_accessible :call_route_id, :var_in, :var_out, :pattern, :replacement, :action, :mandatory, :position + + belongs_to :call_route + + acts_as_list :scope => :call_route + + validates :action, + :presence => true, + :inclusion => { :in => ELEMENT_ACTIONS } + + + def to_s + "#{pattern} => #{var_in} #{var_out}" + end + + def move_up? + #return self.position.to_i > RouteElement.where(:call_route_id => self.call_route_id ).order(:position).first.position.to_i + end + + def move_down? + #return self.position.to_i < RouteElement.where(:call_route_id => self.call_route_id ).order(:position).last.position.to_i + end +end diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb index 8459265..d35f9b4 100644 --- a/app/models/sip_account.rb +++ b/app/models/sip_account.rb @@ -10,7 +10,7 @@ class SipAccount < ActiveRecord::Base # Associations: # - belongs_to :sip_accountable, :polymorphic => true + belongs_to :sip_accountable, :polymorphic => true, :touch => true has_many :phone_sip_accounts, :uniq => true has_many :phones, :through => :phone_sip_accounts @@ -71,7 +71,7 @@ class SipAccount < ActiveRecord::Base after_update :log_out_phone_if_not_local def to_s - truncate((self.caller_name || "SipAccount ID #{self.id}"), :length => TO_S_MAX_CALLER_NAME_LENGTH) + " (#{truncate(self.auth_name, :length => TO_S_MAX_LENGTH_OF_AUTH_NAME)}@...#{self.host.split(/\./)[2,3].to_a.join('.') if self.host })" + truncate((self.caller_name || "SipAccount ID #{self.id}"), :length => GsParameter.get('TO_S_MAX_CALLER_NAME_LENGTH')) + " (#{truncate(self.auth_name, :length => GsParameter.get('TO_S_MAX_LENGTH_OF_AUTH_NAME'))}@...#{self.host.split(/\./)[2,3].to_a.join('.') if self.host })" end def call_forwarding_toggle( call_forwarding_service, to_voicemail = nil ) @@ -200,7 +200,7 @@ class SipAccount < ActiveRecord::Base # log out phone if sip_account is not on this node def log_out_phone_if_not_local - if self.gs_node_id && ! GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS, :id => self.gs_node_id).first + if self.gs_node_id && ! GsNode.where(:ip_address => GsParameter.get('HOMEBASE_IP_ADDRESS'), :id => self.gs_node_id).first self.phones.each do |phone| phone.user_logout; end diff --git a/app/models/tenant.rb b/app/models/tenant.rb index d9351b7..419ac3a 100644 --- a/app/models/tenant.rb +++ b/app/models/tenant.rb @@ -1,15 +1,8 @@ # encoding: UTF-8 class Tenant < ActiveRecord::Base - attr_accessible :name, :description, :sip_domain_id, :country_id, :language_id, :from_field_pin_change_email, :from_field_voicemail_email - - if STRICT_INTERNAL_EXTENSION_HANDLING == true - attr_accessible :internal_extension_ranges - end - - if STRICT_DID_HANDLING == true - attr_accessible :did_list - end + # https://github.com/rails/strong_parameters + include ActiveModel::ForbiddenAttributesProtection # Associations: # @@ -93,7 +86,7 @@ class Tenant < ActiveRecord::Base name end - if STRICT_INTERNAL_EXTENSION_HANDLING == true + if GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') == true def array_of_internal_extension_numbers ranges = self.internal_extension_ranges.gsub(/[^0-9\-,]/,'').gsub(/[\-]+/,'-').gsub(/[,]+/,',').split(/,/) output = [] @@ -112,7 +105,7 @@ class Tenant < ActiveRecord::Base # Generate the internal_extensions # def generate_internal_extensions - internal_extensions = self.phone_number_ranges.find_or_create_by_name(INTERNAL_EXTENSIONS, :description => 'A list of all available internal extensions.') + internal_extensions = self.phone_number_ranges.find_or_create_by_name(GsParameter.get('INTERNAL_EXTENSIONS'), :description => 'A list of all available internal extensions.') phone_number_list = Array.new @@ -122,7 +115,7 @@ class Tenant < ActiveRecord::Base elsif # Don't create extensions like 911, 110 or 112 (at least by default) # - phone_number_list = (self.array_of_internal_extension_numbers - self.country.phone_number_ranges.where(:name => SERVICE_NUMBERS).first.phone_numbers.map{|entry| entry.number}) + phone_number_list = (self.array_of_internal_extension_numbers - self.country.phone_number_ranges.where(:name => GsParameter.get('SERVICE_NUMBERS')).first.phone_numbers.map{|entry| entry.number}) end end @@ -133,7 +126,7 @@ class Tenant < ActiveRecord::Base end - if STRICT_DID_HANDLING == true + if GsParameter.get('STRICT_DID_HANDLING') == true def array_of_dids_generated_from_did_list numbers = self.did_list.downcase.gsub(/[^0-9,x\+]/,'').gsub(/[,]+/,',').split(/,/) array_of_all_external_numbers = [] @@ -152,7 +145,7 @@ class Tenant < ActiveRecord::Base # Generate the external numbers (DIDs) # def generate_dids - dids = self.phone_number_ranges.find_or_create_by_name(DIRECT_INWARD_DIALING_NUMBERS, :description => 'A list of all available DIDs.') + dids = self.phone_number_ranges.find_or_create_by_name(GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS'), :description => 'A list of all available DIDs.') self.array_of_dids_generated_from_did_list.each do |number| dids.phone_numbers.find_or_create_by_name_and_number('DID', number) end @@ -167,7 +160,7 @@ class Tenant < ActiveRecord::Base @internal_extensions_and_dids ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). where(:phone_numberable_id => self.phone_number_ranges. - where(:name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS]). + where(:name => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')]). map{|pnr| pnr.id }) end @@ -175,7 +168,7 @@ class Tenant < ActiveRecord::Base @array_of_internal_extensions ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). where(:phone_numberable_id => self.phone_number_ranges. - where(:name => INTERNAL_EXTENSIONS). + where(:name => GsParameter.get('INTERNAL_EXTENSIONS')). map{|pnr| pnr.id }). map{|phone_number| phone_number.number }. sort.uniq @@ -184,7 +177,7 @@ class Tenant < ActiveRecord::Base def array_of_dids @array_of_dids ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). - where(:phone_numberable_id => self.phone_number_ranges.where(:name => DIRECT_INWARD_DIALING_NUMBERS).map{|pnr| pnr.id }). + where(:phone_numberable_id => self.phone_number_ranges.where(:name => GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')).map{|pnr| pnr.id }). map{|phone_number| phone_number.to_s }. sort.uniq end @@ -215,7 +208,7 @@ class Tenant < ActiveRecord::Base # Create a public phone book for this tenant def create_a_default_phone_book - if self.name != SUPER_TENANT_NAME + if self.name != GsParameter.get('SUPER_TENANT_NAME') general_phone_book = self.phone_books.find_or_create_by_name_and_description( I18n.t('phone_books.general_phone_book.name'), I18n.t('phone_books.general_phone_book.description', :resource => self.to_s) diff --git a/app/models/user.rb b/app/models/user.rb index 2d0256f..b902b99 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -27,7 +27,8 @@ class User < ActiveRecord::Base } validates_length_of [:new_pin, :new_pin_confirmation], - :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), + :maximum => (GsParameter.get('MAXIMUM_PIN_LENGTH').nil? ? 10 : GsParameter.get('MAXIMUM_PIN_LENGTH')), :allow_blank => true, :allow_nil => true validates_format_of [:new_pin, :new_pin_confirmation], :with => /^[0-9]+$/, @@ -202,6 +203,7 @@ class User < ActiveRecord::Base else phone.destroy end + phone.resync end end |