diff options
168 files changed, 3325 insertions, 944 deletions
@@ -58,13 +58,10 @@ gem "mini_magick" # Pagination https://github.com/mislav/will_paginate/wiki/Installation gem 'will_paginate' -# DelayedJob -gem 'delayed_job' +# DelayedJob https://github.com/collectiveidea/delayed_job +gem 'daemons' gem 'delayed_job_active_record' -# Private Pub http://railscasts.com/episodes/316-private-pub -gem 'private_pub' - # https://github.com/iain/http_accept_language gem 'http_accept_language' @@ -79,6 +76,12 @@ gem 'unicorn' gem 'thin' +# Backup https://github.com/meskyanichi/backup +gem 'backup' + +# Cronjobs +gem 'whenever' + # Local Variables: # mode: ruby # End: diff --git a/Gemfile.lock b/Gemfile.lock index 33e77ff..8491109 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,12 +29,14 @@ GEM i18n (~> 0.6) multi_json (~> 1.0) acts_as_list (0.1.9) - addressable (2.3.2) arel (3.0.2) + backup (3.0.27) + open4 (~> 1.3.0) + thor (>= 0.15.4, < 2) bcrypt-ruby (3.0.1) - better_errors (0.3.2) + better_errors (0.5.0) coderay (>= 1.0.0) - erubis (>= 2.7.0) + erubis (>= 2.6.6) binding_of_caller (0.6.8) breadcrumbs_on_rails (2.3.0) builder (3.0.4) @@ -44,6 +46,7 @@ GEM carrierwave (0.8.0) activemodel (>= 3.2.0) activesupport (>= 3.2.0) + chronic (0.9.0) chunky_png (1.2.7) coderay (1.0.8) coffee-rails (3.2.2) @@ -59,53 +62,34 @@ GEM sass (~> 3.1) compass-rails (1.0.3) compass (>= 0.12.2, < 0.14) - cookiejar (0.3.0) daemons (1.1.9) dalli (2.6.2) - delayed_job (3.0.4) + delayed_job (3.0.5) activesupport (~> 3.0) - delayed_job_active_record (0.3.3) + delayed_job_active_record (0.4.0) activerecord (>= 2.1.0, < 4) delayed_job (~> 3.0) - em-http-request (1.0.3) - addressable (>= 2.2.3) - cookiejar - em-socksify - eventmachine (>= 1.0.0.beta.4) - http_parser.rb (>= 0.5.3) - em-socksify (0.2.1) - eventmachine (>= 1.0.0.beta.4) erubis (2.7.0) eventmachine (1.0.0) execjs (1.4.0) multi_json (~> 1.0) factory_girl (4.2.0) activesupport (>= 3.0.0) - factory_girl_rails (4.2.0) + factory_girl_rails (4.2.1) factory_girl (~> 4.2.0) railties (>= 3.0.0) - faye (0.8.8) - cookiejar (>= 0.3.0) - em-http-request (>= 0.3.0) - eventmachine (>= 0.12.0) - faye-websocket (>= 0.4.0) - rack (>= 1.0.0) - yajl-ruby (>= 1.0.0) - faye-websocket (0.4.6) - eventmachine (>= 0.12.0) fssm (0.2.10) haml (3.1.7) hike (1.2.1) hirb (0.7.1) http_accept_language (1.0.2) - http_parser.rb (0.5.3) i18n (0.6.1) inifile (2.0.2) journey (1.0.4) - jquery-rails (2.2.0) + jquery-rails (2.2.1) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) - json (1.7.6) + json (1.7.7) kgio (2.8.0) macaddr (1.6.1) systemu (~> 2.5.0) @@ -113,21 +97,20 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - mime-types (1.19) + mime-types (1.21) mini_magick (3.4) subexec (~> 0.2.1) - multi_json (1.5.0) + multi_json (1.5.1) mysql2 (0.3.11) nokogiri (1.5.6) + open4 (1.3.0) polyglot (0.3.3) - private_pub (1.0.3) - faye quiet_assets (1.0.1) railties (~> 3.1) - rack (1.4.4) + rack (1.4.5) rack-cache (1.2) rack (>= 0.4) - rack-ssl (1.3.2) + rack-ssl (1.3.3) rack rack-test (0.6.2) rack (>= 1.0) @@ -148,7 +131,7 @@ GEM thor (>= 0.14.6, < 2.0) raindrops (0.10.0) rake (10.0.3) - rdoc (3.12) + rdoc (3.12.1) json (~> 1.4) sass (3.2.5) sass-rails (3.2.6) @@ -187,20 +170,23 @@ GEM uglifier (1.3.0) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) - unicorn (4.5.0) + unicorn (4.6.0) kgio (~> 2.6) rack raindrops (~> 0.7) uuid (2.3.6) macaddr (~> 1.0) + whenever (0.8.2) + activesupport (>= 2.3.4) + chronic (>= 0.6.3) will_paginate (3.0.4) - yajl-ruby (1.1.0) PLATFORMS ruby DEPENDENCIES acts_as_list + backup bcrypt-ruby better_errors binding_of_caller @@ -210,8 +196,8 @@ DEPENDENCIES carrierwave coffee-rails (~> 3.2.1) compass-rails + daemons dalli - delayed_job delayed_job_active_record factory_girl factory_girl_rails @@ -224,7 +210,6 @@ DEPENDENCIES mini_magick mysql2 nokogiri - private_pub quiet_assets rails (= 3.2.11) sass-rails @@ -237,4 +222,5 @@ DEPENDENCIES uglifier (>= 1.3.0) unicorn uuid + whenever will_paginate diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 9097d83..c6f4107 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,5 +11,6 @@ // GO AFTER THE REQUIRES BELOW. // //= require jquery +//= require jquery-ui //= require jquery_ujs //= require_tree . diff --git a/app/assets/javascripts/call_route.js.coffee b/app/assets/javascripts/call_route.js.coffee new file mode 100644 index 0000000..fab7f10 --- /dev/null +++ b/app/assets/javascripts/call_route.js.coffee @@ -0,0 +1,6 @@ +jQuery -> + $('.call_routes').sortable + axis: 'y' + handle: '.handle' + update: -> + $.post($(this).data('update-url'), $(this).sortable('serialize'))
\ No newline at end of file diff --git a/app/assets/javascripts/phone_number.js.coffee b/app/assets/javascripts/phone_number.js.coffee new file mode 100644 index 0000000..ee983ee --- /dev/null +++ b/app/assets/javascripts/phone_number.js.coffee @@ -0,0 +1,6 @@ +jQuery -> + $('#phone_numbers').sortable + axis: 'y' + handle: '.handle' + update: -> + $.post($(this).data('update-url'), $(this).sortable('serialize'))
\ No newline at end of file diff --git a/app/assets/javascripts/route_element.js.coffee b/app/assets/javascripts/route_element.js.coffee new file mode 100644 index 0000000..75dc553 --- /dev/null +++ b/app/assets/javascripts/route_element.js.coffee @@ -0,0 +1,6 @@ +jQuery -> + $('#route_elements').sortable + axis: 'y' + handle: '.handle' + update: -> + $.post($(this).data('update-url'), $(this).sortable('serialize'))
\ No newline at end of file diff --git a/app/assets/javascripts/softkey.js.coffee b/app/assets/javascripts/softkey.js.coffee new file mode 100644 index 0000000..a8d2d0c --- /dev/null +++ b/app/assets/javascripts/softkey.js.coffee @@ -0,0 +1,6 @@ +jQuery -> + $('#softkeys').sortable + axis: 'y' + handle: '.handle' + update: -> + $.post($(this).data('update-url'), $(this).sortable('serialize'))
\ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 9093f8e..44868e4 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -12,4 +12,8 @@ *= require bootstrap/bootstrap *= require bootstrap/bootstrap-responsive *= require gemeinschaft-generic + *= require call_routes + *= require softkeys + *= require phone_numbers + *= require route_elements */ diff --git a/app/assets/stylesheets/call_routes.css.scss b/app/assets/stylesheets/call_routes.css.scss new file mode 100644 index 0000000..d39e1d1 --- /dev/null +++ b/app/assets/stylesheets/call_routes.css.scss @@ -0,0 +1,5 @@ +.call_routes .handle { + font-size: 12px; + color: #777; + cursor: move; +}
\ No newline at end of file diff --git a/app/assets/stylesheets/phone_numbers.css.scss b/app/assets/stylesheets/phone_numbers.css.scss new file mode 100644 index 0000000..141a1f7 --- /dev/null +++ b/app/assets/stylesheets/phone_numbers.css.scss @@ -0,0 +1,5 @@ +#phone_numbers .handle { + font-size: 12px; + color: #777; + cursor: move; +}
\ No newline at end of file diff --git a/app/assets/stylesheets/route_elements.css.scss b/app/assets/stylesheets/route_elements.css.scss new file mode 100644 index 0000000..a0080ab --- /dev/null +++ b/app/assets/stylesheets/route_elements.css.scss @@ -0,0 +1,5 @@ +#route_elements .handle { + font-size: 12px; + color: #777; + cursor: move; +}
\ No newline at end of file diff --git a/app/assets/stylesheets/softkeys.css.scss b/app/assets/stylesheets/softkeys.css.scss new file mode 100644 index 0000000..425c6f1 --- /dev/null +++ b/app/assets/stylesheets/softkeys.css.scss @@ -0,0 +1,5 @@ +#softkeys .handle { + font-size: 12px; + color: #777; + cursor: move; +}
\ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e4165f3..d1d918e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,26 +2,21 @@ class ApplicationController < ActionController::Base protect_from_forgery - before_filter :set_locale + before_filter :start_setup_if_new_installation - before_filter :go_to_setup_if_new_installation - before_filter :home_breadcrumb - + before_filter :set_locale helper_method :current_user - + helper_method :guess_local_ip_address helper_method :guess_local_host - + + before_filter :home_breadcrumb + helper_method :'have_https?' + helper_method :'single_sign_on_system?' helper_method :random_pin - - #TODO Add check_authorization. See - # https://github.com/ryanb/cancan - # https://github.com/ryanb/cancan/wiki/Ensure-Authorization - # and Gemeinschaft 4 - # Generate a new name for an Object # def generate_a_new_name(parent, child = nil) @@ -56,6 +51,8 @@ class ApplicationController < ActionController::Base def random_pin if GsParameter.get('MINIMUM_PIN_LENGTH') > 0 (1..GsParameter.get('MINIMUM_PIN_LENGTH')).map{|i| (0 .. 9).to_a.sample}.join + else + (1..8).map{|i| (0 .. 9).to_a.sample}.join end end @@ -106,33 +103,41 @@ class ApplicationController < ActionController::Base end rescue_from CanCan::AccessDenied do |exception| - if @current_user + if current_user redirect_to root_url, :alert => 'Access denied! Please ask your admin to grant you the necessary rights.' else - if Tenant.count == 0 && User.count == 0 - # This is a brand new system. We need to run a setup first. - redirect_to wizards_new_initial_setup_path - else - # You need to login first. - redirect_to log_in_path, :alert => 'Access denied! You need to login first.' - end + # You need to login first. + redirect_to log_in_path, :alert => 'Access denied! You need to login first.' end end private - def current_user - begin - @current_user ||= User.find(session[:user_id]) if session[:user_id] - rescue ActiveRecord::RecordNotFound - session[:user_id] = nil + def current_user + if session[:user_id].nil? && single_sign_on_system? + auth_user = User.where(:user_name => request.env[GsParameter.get('SingleSignOnEnvUserNameKey')]).first + else + if session[:user_id] && User.where(:id => session[:user_id]).any? + auth_user = User.where(:id => session[:user_id]).first + else + auth_user = nil + end + end + session[:user_id] = auth_user.try(:id) + return auth_user + end + + def single_sign_on_system? + if GsParameter.get('SingleSignOnEnvUserNameKey').blank? + false + else + true end - @current_user - end + end - def go_to_setup_if_new_installation + def start_setup_if_new_installation if Rails.env != 'test' - if GemeinschaftSetup.all.count == 0 + if GemeinschaftSetup.count == 0 redirect_to new_gemeinschaft_setup_path end end diff --git a/app/controllers/backup_jobs_controller.rb b/app/controllers/backup_jobs_controller.rb new file mode 100644 index 0000000..31b9c21 --- /dev/null +++ b/app/controllers/backup_jobs_controller.rb @@ -0,0 +1,46 @@ +class BackupJobsController < ApplicationController + load_and_authorize_resource :backup_job + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + # Do the same as create. + # + @backup_job = BackupJob.new(:started_at => Time.now) + + if @backup_job.save + redirect_to backup_jobs_path, :notice => t('backup_jobs.controller.successfuly_created') + else + render :new + end + end + + def create + @backup_job = BackupJob.new(:started_at => Time.now) + + if @backup_job.save + redirect_to backup_jobs_path, :notice => t('backup_jobs.controller.successfuly_created') + else + render :new + end + end + + def destroy + @backup_job.destroy + redirect_to backup_jobs_url, :notice => t('backup_jobs.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + add_breadcrumb t("backup_jobs.index.page_title"), backup_jobs_path + if @backup_job && !@backup_job.new_record? + add_breadcrumb @backup_job, @backup_job + end + end +end diff --git a/app/controllers/call_forwards_controller.rb b/app/controllers/call_forwards_controller.rb index 001ed60..b1ced87 100644 --- a/app/controllers/call_forwards_controller.rb +++ b/app/controllers/call_forwards_controller.rb @@ -28,7 +28,7 @@ class CallForwardsController < ApplicationController @available_call_forward_cases = [] CallForwardCase.all.each do |available_call_forward_case| - if GuiFunction.display?("call_forward_case_#{available_call_forward_case.value}_field_in_call_forward_form", @current_user) + if GuiFunction.display?("call_forward_case_#{available_call_forward_case.value}_field_in_call_forward_form", current_user) @available_call_forward_cases << available_call_forward_case end end @@ -112,7 +112,7 @@ class CallForwardsController < ApplicationController voice_mail_destination, ] - if GuiFunction.display?('huntgroup_in_destination_field_in_call_forward_form', @current_user) + if GuiFunction.display?('huntgroup_in_destination_field_in_call_forward_form', current_user) HuntGroup.all.each do |hunt_group| hunt_group_destination = CallForwardingDestination.new() hunt_group_destination.id = "#{hunt_group.id}:HuntGroup" diff --git a/app/controllers/call_routes_controller.rb b/app/controllers/call_routes_controller.rb index 0259a10..2dcd648 100644 --- a/app/controllers/call_routes_controller.rb +++ b/app/controllers/call_routes_controller.rb @@ -1,5 +1,11 @@ class CallRoutesController < ApplicationController - authorize_resource :call_route + authorize_resource :call_route, :except => [:sort] + + before_filter { |controller| + if !params[:call_route].blank? && !params[:call_route][:endpoint_str].blank? + params[:call_route][:endpoint_type], delimeter, params[:call_route][:endpoint_id] = params[:call_route][:endpoint_str].partition('=') + end + } def index @call_routes = CallRoute.order([:routing_table, :position]) @@ -14,6 +20,11 @@ class CallRoutesController < ApplicationController def new @call_route = CallRoute.new + @endpoints = Gateway.all.collect {|r| [ "gateway: #{r.to_s}", "gateway=#{r.id}" ] } + @endpoints << [ 'phonenumber', 'phonenumber=' ] + @endpoints << [ 'dialplanfunction', 'dialplanfunction=' ] + @endpoints << [ 'hangup', 'hangup=' ] + @endpoints << [ 'unknown', 'unknown=' ] spread_breadcrumbs end @@ -29,12 +40,18 @@ class CallRoutesController < ApplicationController def edit @call_route = CallRoute.find(params[:id]) + @endpoints = Gateway.all.collect {|r| [ "gateway: #{r.to_s}", "gateway=#{r.id}" ] } + @endpoints << [ 'phonenumber', 'phonenumber=' ] + @endpoints << [ 'dialplanfunction', 'dialplanfunction=' ] + @endpoints << [ 'hangup', 'hangup=' ] + @endpoints << [ 'unknown', 'unknown=' ] spread_breadcrumbs end def update @call_route = CallRoute.find(params[:id]) spread_breadcrumbs + if @call_route.update_attributes(call_route_parameter_params) redirect_to @call_route, :notice => t('call_routes.controller.successfuly_updated') else @@ -48,21 +65,31 @@ class CallRoutesController < ApplicationController redirect_to call_routes_url, :notice => t('call_routes.controller.successfuly_destroyed') end - def move_higher - @call_route = CallRoute.find(params[:id]) - @call_route.move_higher - redirect_to :back + def sort + params[:call_route].each_with_index do |id, index| + CallRoute.update_all({position: index+1}, {id: id}) + #CallRoute.find(:id).move_to_bottom + end + render nothing: true end - def move_lower - @call_route = CallRoute.find(params[:id]) - @call_route.move_lower - redirect_to :back + def show_variables + @channel_variables = Hash.new() + file_name = '/var/log/freeswitch/variables' + if File.readable?(file_name) + File.readlines(file_name).each do |line| + key, delimeter, value = line.partition(': ') + key = to_channel_variable_name(key) + if !key.blank? + @channel_variables[key] = URI.unescape(value.gsub(/\n/, '')); + end + end + end end private def call_route_parameter_params - params.require(:call_route).permit(:routing_table, :name, :endpoint_type, :endpoint_id) + params.require(:call_route).permit(:routing_table, :name, :endpoint_type, :endpoint_id, :position) end def spread_breadcrumbs @@ -72,4 +99,50 @@ class CallRoutesController < ApplicationController end end + def to_channel_variable_name(name) + variables_map = { + 'Channel-State' => 'state', + 'Channel-State-Number' => 'state_number', + 'Channel-Name' => 'channel_name', + 'Unique-ID' => 'uuid', + 'Call-Direction' => 'direction', + 'Answer-State' => 'state', + 'Channel-Read-Codec-Name' => 'read_codec', + 'Channel-Read-Codec-Rate' => 'read_rate', + 'Channel-Write-Codec-Name' => 'write_codec', + 'Channel-Write-Codec-Rate' => 'write_rate', + 'Caller-Username' => 'username', + 'Caller-Dialplan' => 'dialplan', + 'Caller-Caller-ID-Name' => 'caller_id_name', + 'Caller-Caller-ID-Number' => 'caller_id_number', + 'Caller-ANI' => 'ani', + 'Caller-ANI-II' => 'aniii', + 'Caller-Network-Addr' => 'network_addr', + 'Caller-Destination-Number' => 'destination_number', + 'Caller-Unique-ID' => 'uuid', + 'Caller-Source' => 'source', + 'Caller-Context' => 'context', + 'Caller-RDNIS' => 'rdnis', + 'Caller-Channel-Name' => 'channel_name', + 'Caller-Profile-Index' => 'profile_index', + 'Caller-Channel-Created-Time' => 'created_time', + 'Caller-Channel-Answered-Time' => 'answered_time', + 'Caller-Channel-Hangup-Time' => 'hangup_time', + 'Caller-Channel-Transfer-Time' => 'transfer_time', + 'Caller-Screen-Bit' => 'screen_bit', + 'Caller-Privacy-Hide-Name' => 'privacy_hide_name', + 'Caller-Privacy-Hide-Number' => 'privacy_hide_number', + } + + name = name.gsub(/[^a-zA-Z1-9_\-]/, '') + + if variables_map[name] + return variables_map[name] + elsif name.match(/^variable_/) + return name.gsub(/^variable_/, '') + end + + return nil + end + end diff --git a/app/controllers/config_polycom_controller.rb b/app/controllers/config_polycom_controller.rb index 9d44e51..fd730e3 100644 --- a/app/controllers/config_polycom_controller.rb +++ b/app/controllers/config_polycom_controller.rb @@ -26,12 +26,15 @@ class ConfigPolycomController < ApplicationController if ! params[:sip_account].blank? @sip_account = @phone.sip_accounts.where({ :id => params[:sip_account].to_i }).first + if ! @sip_account && @phone.fallback_sip_account && @phone.fallback_sip_account.id == params[:sip_account].to_i + @sip_account = @phone.fallback_sip_account + end if ! @sip_account render( :status => 404, :layout => false, :content_type => 'text/plain', - :text => "<!-- SipAccount not found -->", + :text => "<!-- SipAccount ID:#{params[:sip_account]} not found -->", ) return false end @@ -113,37 +116,41 @@ class ConfigPolycomController < ApplicationController softkey_index = 1 blf_index = 0 - @phone.sip_accounts.each do |sip_account| - sip_account_index = 0 - if (sip_account.sip_accountable_type == @phone.phoneable_type) and (sip_account.sip_accountable_id == @phone.phoneable_id) - sip_account_index += 1 - if sip_account_index == 1 - xml_applications_url = "#{request.protocol}#{request.host_with_port}/config_polycom/#{@phone.id}/#{sip_account.id}" - @settings['voIpProt.SIP.outboundProxy.address'] = sip_account.host - @settings['voIpProt.SIP.outboundProxy.port'] = SIP_DEFAULT_PORT - end + phone_sip_accounts = Array.new() + if @phone.sip_accounts && @phone.sip_accounts.count > 0 + phone_sip_accounts = @phone.sip_accounts + elsif @phone.fallback_sip_account + phone_sip_accounts.push( @phone.fallback_sip_account ) + end + sip_account_index = 0 + phone_sip_accounts.each do |sip_account| + sip_account_index += 1 + if sip_account_index == 1 + xml_applications_url = "#{request.protocol}#{request.host_with_port}/config_polycom/#{@phone.id}/#{sip_account.id}" + @settings['voIpProt.SIP.outboundProxy.address'] = sip_account.host + @settings['voIpProt.SIP.outboundProxy.port'] = SIP_DEFAULT_PORT + end - @settings["reg.#{sip_account_index}.address"] = "#{sip_account.auth_name}@#{sip_account.host}" - @settings["reg.#{sip_account_index}.auth.password"] = sip_account.password - @settings["reg.#{sip_account_index}.auth.userId"] = sip_account.auth_name - @settings["reg.#{sip_account_index}.displayName"] = 'Call' - @settings["reg.#{sip_account_index}.label"] = sip_account.caller_name - @settings["voIpProt.server.#{sip_account_index}.address"] = sip_account.host - @settings["voIpProt.server.#{sip_account_index}.port"] = SIP_DEFAULT_PORT - @settings["call.missedCallTracking.#{sip_account_index}.enabled"] = 0 - - sip_account.softkeys.order(:position).each do |softkey| - softkey_index += 1 - if softkey.softkey_function - softkey_function = softkey.softkey_function.name - end - case softkey_function - when 'blf' - blf_index += 1 - @settings["lineKey.#{softkey_index}.category"] = 'BLF' - @settings["attendant.resourceList.#{blf_index}.address"] = "#{softkey.number}@#{sip_account.host}" - @settings["attendant.resourceList.#{blf_index}.label"] = softkey.label - end + @settings["reg.#{sip_account_index}.address"] = "#{sip_account.auth_name}@#{sip_account.host}" + @settings["reg.#{sip_account_index}.auth.password"] = sip_account.password + @settings["reg.#{sip_account_index}.auth.userId"] = sip_account.auth_name + @settings["reg.#{sip_account_index}.displayName"] = 'Call' + @settings["reg.#{sip_account_index}.label"] = sip_account.caller_name + @settings["voIpProt.server.#{sip_account_index}.address"] = sip_account.host + @settings["voIpProt.server.#{sip_account_index}.port"] = SIP_DEFAULT_PORT + @settings["call.missedCallTracking.#{sip_account_index}.enabled"] = 0 + + sip_account.softkeys.order(:position).each do |softkey| + softkey_index += 1 + if softkey.softkey_function + softkey_function = softkey.softkey_function.name + end + case softkey_function + when 'blf' + blf_index += 1 + @settings["lineKey.#{softkey_index}.category"] = 'BLF' + @settings["attendant.resourceList.#{blf_index}.address"] = "#{softkey.number}@#{sip_account.host}" + @settings["attendant.resourceList.#{blf_index}.label"] = softkey.label end end end diff --git a/app/controllers/config_siemens_controller.rb b/app/controllers/config_siemens_controller.rb index b7fa107..bbeba46 100644 --- a/app/controllers/config_siemens_controller.rb +++ b/app/controllers/config_siemens_controller.rb @@ -610,15 +610,21 @@ class ConfigSiemensController < ApplicationController @new_settings << ['stimulus-led-control-uri', key_idx, '' ] @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] when 'call_forwarding' + if sk.softkeyable.class == CallForward then @new_settings << ['function-key-def', key_idx, '63'] - @new_settings << ['stimulus-led-control-uri', key_idx, "f-cftg-#{sk.call_forward_id}" ] + @new_settings << ['stimulus-led-control-uri', key_idx, "f-cftg-#{sk.softkeyable.id}" ] @new_settings << ['send-url-address', key_idx, request.host] @new_settings << ['send-url-protocol', key_idx, 3] @new_settings << ['send-url-port', key_idx, '80'] @new_settings << ['send-url-path', key_idx, "/config_siemens/#{@phone.id}/#{@sip_account.id}/call_forwarding.xml"] - @new_settings << ['send-url-query', key_idx, "id=#{sk.call_forward_id}&function=toggle"] + @new_settings << ['send-url-query', key_idx, "id=#{sk.softkeyable.id}&function=toggle"] @new_settings << ['send-url-method', key_idx, '0'] @new_settings << ['blf-popup', key_idx, 'false'] + else + @new_settings << ['function-key-def', key_idx, '0'] + @new_settings << ['stimulus-led-control-uri', key_idx, '' ] + @new_settings << ['stimulus-DTMF-sequence', key_idx, '' ] + end when 'call_forwarding_always' phone_number = PhoneNumber.where(:number => sk.number, :phone_numberable_type => 'SipAccount').first if phone_number @@ -887,7 +893,7 @@ class ConfigSiemensController < ApplicationController if @call_forwarding_id call_forwarding = @sip_account.call_forwards.where(:id => @call_forwarding_id).first - if !call_forwarding and @sip_account.softkeys.where(:call_forward_id => @call_forwarding_id).count > 0 + if !call_forwarding and @sip_account.softkeys.where(:softkeyable_id => @call_forwarding_id, :softkeyable_type => 'CallForward').count > 0 call_forwarding = CallForward.where(:id => @call_forwarding_id).first end diff --git a/app/controllers/config_snom_controller.rb b/app/controllers/config_snom_controller.rb index e797a43..58cced2 100644 --- a/app/controllers/config_snom_controller.rb +++ b/app/controllers/config_snom_controller.rb @@ -247,6 +247,7 @@ class ConfigSnomController < ApplicationController elsif @phone.fallback_sip_account phone_sip_accounts.push( @phone.fallback_sip_account ) end + expiry_seconds = GsParameter.get('SIP_EXPIRY_SECONDS') phone_sip_accounts.each do |sip_account| if (sip_account.sip_accountable_type == @phone.phoneable_type) and (sip_account.sip_accountable_id == @phone.phoneable_id) snom_sip_account = { @@ -259,7 +260,8 @@ class ConfigSnomController < ApplicationController :name => sip_account.auth_name, :realname => 'Call', :idle_text => sip_account.caller_name, - :mailbox => "<sip:#{sip_account.auth_name}@#{sip_account.host}>" + :mailbox => "<sip:#{sip_account.auth_name}@#{sip_account.host}>", + :expiry => expiry_seconds, } @sip_accounts.push(snom_sip_account) sip_account_index = @sip_accounts.length @@ -280,23 +282,47 @@ class ConfigSnomController < ApplicationController @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "speed f-li-#{softkey.number}"}) when 'conference' @softkeys.push({:context => sip_account_index, :label => softkey.label, :data => "blf <sip:#{softkey.number}@#{sip_account.host}>|f-ta-"}) - when 'call_forwarding' + when 'call_parking' @softkeys.push({ :context => sip_account_index, - :function => softkey.function, + :function => softkey.softkey_function.name, :label => softkey.label, :softkey => softkey, :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), :subscription => { - :to => "f-cftg-#{softkey.call_forward_id}@#{sip_account.host}", + :to => "park+#{@softkeys.softkeyable_id}@#{sip_account.host}", :for => "#{sip_account.auth_name}@#{sip_account.host}" }, :actions => [{ - :type => :url, - :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/call_forwarding.xml?id=#{softkey.call_forward_id}&function=toggle", + :type => :dial, + :target => "f-tpark-#{@softkeys.softkeyable_id}", + :when => 'on press', + :states => 'connected,holding', + },{ + :type => :dial, + :target => "f-park-#{@softkeys.softkeyable_id}", :when => 'on press', }], }) + when 'call_forwarding' + if softkey.softkeyable.class == CallForward then + @softkeys.push({ + :context => sip_account_index, + :function => softkey.softkey_function.name, + :label => softkey.label, + :softkey => softkey, + :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), + :subscription => { + :to => "f-cftg-#{softkey.softkeyable_id}@#{sip_account.host}", + :for => "#{sip_account.auth_name}@#{sip_account.host}" + }, + :actions => [{ + :type => :url, + :target => "#{request.protocol}#{request.host_with_port}/config_snom/#{@phone.id}/#{snom_sip_account[:id]}/call_forwarding.xml?id=#{softkey.softkeyable_id}&function=toggle", + :when => 'on press', + }], + }) + end when 'call_forwarding_always' phone_number = PhoneNumber.where(:number => softkey.number, :phone_numberable_type => 'SipAccount').first if phone_number @@ -308,7 +334,7 @@ class ConfigSnomController < ApplicationController @softkeys.push({ :context => sip_account_index, - :function => softkey.function, + :function => softkey.softkey_function.name, :label => softkey.label, :softkey => softkey, :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), @@ -333,7 +359,7 @@ class ConfigSnomController < ApplicationController @softkeys.push({ :context => sip_account_index, - :function => softkey.function, + :function => softkey.softkey_function.name, :label => softkey.label, :softkey => softkey, :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), @@ -373,7 +399,7 @@ class ConfigSnomController < ApplicationController if hunt_group_member @softkeys.push({ :context => sip_account_index, - :function => softkey.function, + :function => softkey.softkey_function.name, :label => softkey.label, :softkey => softkey, :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), @@ -403,7 +429,7 @@ class ConfigSnomController < ApplicationController if acd_agent @softkeys.push({ :context => sip_account_index, - :function => softkey.function, + :function => softkey.softkey_function.name, :label => softkey.label, :softkey => softkey, :general_type => t("softkeys.functions.#{softkey.softkey_function.name}"), @@ -922,7 +948,7 @@ AAAA' if @call_forwarding_id call_forwarding = @sip_account.call_forwards.where(:id => @call_forwarding_id).first - if !call_forwarding and @sip_account.softkeys.where(:call_forward_id => @call_forwarding_id).count > 0 + if !call_forwarding and @sip_account.softkeys.where(:softkeyable_id => @call_forwarding_id, :softkeyable_type => 'CallForward').count > 0 call_forwarding = CallForward.where(:id => @call_forwarding_id).first end diff --git a/app/controllers/fax_documents_controller.rb b/app/controllers/fax_documents_controller.rb index eff9604..5653683 100644 --- a/app/controllers/fax_documents_controller.rb +++ b/app/controllers/fax_documents_controller.rb @@ -58,23 +58,18 @@ class FaxDocumentsController < ApplicationController end private + def spread_breadcrumbs - breadcrumbs = [] - breadcrumbs = case @fax_account.fax_accountable.class.to_s - when 'User' ; [ - [@fax_account.fax_accountable.to_s, user_path(@fax_account.fax_accountable)], - [t('fax_accounts.name').pluralize, user_fax_accounts_path(@fax_account.fax_accountable)], - [t('fax_documents.name').pluralize, fax_account_fax_documents_path(@fax_account)], - ] - when 'UserGroup' ; [ - [@fax_account.fax_accountable, user_group_path(@fax_account.fax_accountable)], - [t('fax_accounts.name').pluralize, user_group_fax_accounts_path(@fax_account.fax_accountable)], - [t('fax_documents.name').pluralize, fax_account_fax_documents_path(@fax_account)], - ] + if @fax_account && @fax_account.fax_accountable.class == User + add_breadcrumb t("users.index.page_title"), tenant_users_path(@fax_account.fax_accountable.current_tenant) + add_breadcrumb @fax_account.fax_accountable, tenant_user_path(@fax_account.fax_accountable.current_tenant, @fax_account.fax_accountable) end - if !breadcrumbs.blank? - breadcrumbs.each do |breadcrumb| - add_breadcrumb breadcrumb[0], breadcrumb[1] + + if @fax_account + add_breadcrumb t("fax_accounts.index.page_title"), user_fax_accounts_path(@fax_account.fax_accountable) + add_breadcrumb @fax_account, user_fax_account_path(@fax_account.fax_accountable, @fax_account) + if @fax_document && !@fax_document.new_record? + add_breadcrumb @fax_document, fax_account_fax_document_path(@fax_account, @fax_document) end end end diff --git a/app/controllers/gemeinschaft_setups_controller.rb b/app/controllers/gemeinschaft_setups_controller.rb index 4f4a72a..a62df99 100644 --- a/app/controllers/gemeinschaft_setups_controller.rb +++ b/app/controllers/gemeinschaft_setups_controller.rb @@ -4,9 +4,9 @@ class GemeinschaftSetupsController < ApplicationController # caches_page :new, :gzip => :best_compression - load_and_authorize_resource :gemeinschaft_setup + skip_before_filter :start_setup_if_new_installation - skip_before_filter :go_to_setup_if_new_installation + load_and_authorize_resource :gemeinschaft_setup def new @user = @gemeinschaft_setup.build_user( @@ -23,6 +23,7 @@ class GemeinschaftSetupsController < ApplicationController @gemeinschaft_setup.default_company_name = generate_a_new_name(Tenant.new) @gemeinschaft_setup.default_system_email = 'admin@localhost' + @gemeinschaft_setup.trunk_access_code = '0' end def create @@ -52,7 +53,7 @@ class GemeinschaftSetupsController < ApplicationController CallRoute.factory_defaults_prerouting(@gemeinschaft_setup.country.country_code, @gemeinschaft_setup.country.trunk_prefix, @gemeinschaft_setup.country.international_call_prefix, - '', + @gemeinschaft_setup.trunk_access_code, @gemeinschaft_setup.default_area_code ) diff --git a/app/controllers/gui_functions_controller.rb b/app/controllers/gui_functions_controller.rb index 0cb7898..4b57322 100644 --- a/app/controllers/gui_functions_controller.rb +++ b/app/controllers/gui_functions_controller.rb @@ -58,7 +58,7 @@ class GuiFunctionsController < ApplicationController private def load_user_groups - @user_groups = Tenant.find(@current_user.current_tenant).user_groups.order(:position) + @user_groups = Tenant.find(current_user.current_tenant).user_groups.order(:position) end def spread_breadcrumbs diff --git a/app/controllers/intruders_controller.rb b/app/controllers/intruders_controller.rb new file mode 100644 index 0000000..eb34f2b --- /dev/null +++ b/app/controllers/intruders_controller.rb @@ -0,0 +1,41 @@ +class IntrudersController < ApplicationController + def index + @intruders = Intruder.all + end + + def show + @intruder = Intruder.find(params[:id]) + end + + def new + @intruder = Intruder.new + end + + def create + @intruder = Intruder.new(params[:intruder]) + if @intruder.save + redirect_to @intruder, :notice => t('intruders.controller.successfuly_created') + else + render :new + end + end + + def edit + @intruder = Intruder.find(params[:id]) + end + + def update + @intruder = Intruder.find(params[:id]) + if @intruder.update_attributes(params[:intruder]) + redirect_to @intruder, :notice => t('intruders.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @intruder = Intruder.find(params[:id]) + @intruder.destroy + redirect_to intruders_url, :notice => t('intruders.controller.successfuly_destroyed') + end +end diff --git a/app/controllers/page_controller.rb b/app/controllers/page_controller.rb index 8f4fa88..ed48e3c 100644 --- a/app/controllers/page_controller.rb +++ b/app/controllers/page_controller.rb @@ -2,7 +2,6 @@ class PageController < ApplicationController # load_and_authorize_resource :class => false # CanCan doesn't work here really good because Page is not a resource. - before_filter :if_fresh_system_then_go_to_wizard skip_before_filter :home_breadcrumb, :only => [:index] def index @@ -14,18 +13,5 @@ class PageController < ApplicationController def help end - - private - def if_fresh_system_then_go_to_wizard - if Tenant.count == 0 && User.count == 0 - # This is a brand new system. We need to run a setup first. - redirect_to wizards_new_initial_setup_path - else - if current_user.nil? - # You need to login first. - redirect_to log_in_path, :alert => I18n.t('pages.controller.access_denied_login_first') - end - end - end end diff --git a/app/controllers/phone_numbers_controller.rb b/app/controllers/phone_numbers_controller.rb index c562954..67c4922 100644 --- a/app/controllers/phone_numbers_controller.rb +++ b/app/controllers/phone_numbers_controller.rb @@ -1,22 +1,22 @@ class PhoneNumbersController < ApplicationController - load_resource :phone_book_entry - load_resource :sip_account - load_resource :conference - load_resource :fax_account - load_resource :phone_number_range - load_resource :callthrough - load_resource :whitelist - load_resource :access_authorization - load_resource :hunt_group - load_resource :hunt_group_member - load_resource :automatic_call_distributor - load_and_authorize_resource :phone_number, :through => [:phone_book_entry, :sip_account, :conference, + load_resource :phone_book_entry, :except => [:sort] + load_resource :sip_account, :except => [:sort] + load_resource :conference, :except => [:sort] + load_resource :fax_account, :except => [:sort] + load_resource :phone_number_range, :except => [:sort] + load_resource :callthrough, :except => [:sort] + load_resource :whitelist, :except => [:sort] + load_resource :access_authorization, :except => [:sort] + load_resource :hunt_group, :except => [:sort] + load_resource :hunt_group_member, :except => [:sort] + load_resource :automatic_call_distributor, :except => [:sort] + load_and_authorize_resource :phone_number, :except => [:sort], :through => [:phone_book_entry, :sip_account, :conference, :fax_account, :phone_number_range, :callthrough, :whitelist, :access_authorization, :hunt_group, :hunt_group_member, :automatic_call_distributor] - before_filter :set_and_authorize_parent - before_filter :spread_breadcrumbs + before_filter :set_and_authorize_parent, :except => [:sort] + before_filter :spread_breadcrumbs, :except => [:sort] def index end @@ -67,16 +67,6 @@ class PhoneNumbersController < ApplicationController redirect_to m.(), :notice => t('phone_numbers.controller.successfuly_destroyed') end - def move_higher - @phone_number.move_higher - redirect_to :back - end - - def move_lower - @phone_number.move_lower - redirect_to :back - end - def call sip_account = nil current_user.sip_accounts.each do |user_sip_account| @@ -94,6 +84,13 @@ class PhoneNumbersController < ApplicationController redirect_to(:back) end + def sort + params[:phone_number].each_with_index do |id, index| + PhoneNumber.update_all({position: index+1}, {id: id}) + end + render nothing: true + end + private def set_and_authorize_parent @parent = @phone_book_entry || @sip_account || @conference || @fax_account || diff --git a/app/controllers/route_elements_controller.rb b/app/controllers/route_elements_controller.rb index c4e4c1a..9c9033e 100644 --- a/app/controllers/route_elements_controller.rb +++ b/app/controllers/route_elements_controller.rb @@ -5,7 +5,7 @@ class RouteElementsController < ApplicationController before_filter :spread_breadcrumbs def index - @route_elements = @call_route.route_elements + @route_elements = @call_route.route_elements.order([:position]) end def show @@ -44,14 +44,14 @@ class RouteElementsController < ApplicationController redirect_to call_route_route_elements_path(@call_route), :notice => t('route_elements.controller.successfuly_destroyed') end - def move_higher - @route_element.move_higher - redirect_to :back - end + def sort + #call_route = RouteElement.find(params[:route_element].first).call_route + + params[:route_element].each do |route_element_id| + @call_route.route_elements.find(route_element_id).move_to_bottom + end - def move_lower - @route_element.move_lower - redirect_to :back + render nothing: true end private diff --git a/app/controllers/softkeys_controller.rb b/app/controllers/softkeys_controller.rb index d2a2bb9..c9e8c20 100644 --- a/app/controllers/softkeys_controller.rb +++ b/app/controllers/softkeys_controller.rb @@ -1,9 +1,9 @@ class SoftkeysController < ApplicationController - load_and_authorize_resource :sip_account - load_and_authorize_resource :softkey, :through => [:sip_account] + load_and_authorize_resource :sip_account, :except => [:sort] + load_and_authorize_resource :softkey, :through => [:sip_account], :except => [:sort] before_filter :set_available_call_forwards_and_softkey_functions, :only => [ :new, :edit, :update ] - before_filter :spread_breadcrumbs + before_filter :spread_breadcrumbs, :except => [:sort] def index end @@ -44,16 +44,17 @@ class SoftkeysController < ApplicationController redirect_to sip_account_softkeys_path(@softkey.sip_account), :notice => t('softkeys.controller.successfuly_destroyed') end - def move_higher - @softkey.move_higher - redirect_to :back - end + def sort + sip_account = Softkey.find(params[:softkey].first).sip_account + + params[:softkey].each do |softkey_id| + sip_account.softkeys.find(softkey_id).move_to_bottom + end - def move_lower - @softkey.move_lower - redirect_to :back + render nothing: true end + private def set_available_call_forwards_and_softkey_functions @@ -61,7 +62,7 @@ class SoftkeysController < ApplicationController @softkey_functions = [] SoftkeyFunction.accessible_by(current_ability, :read).each do |softkey_function| - if GuiFunction.display?("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", @current_user) + if GuiFunction.display?("softkey_function_#{softkey_function.name.downcase}_field_in_softkey_form", current_user) @softkey_functions << softkey_function end end diff --git a/app/controllers/system_messages_controller.rb b/app/controllers/system_messages_controller.rb deleted file mode 100644 index d7fe515..0000000 --- a/app/controllers/system_messages_controller.rb +++ /dev/null @@ -1,30 +0,0 @@ -class SystemMessagesController < ApplicationController - load_and_authorize_resource :user - load_and_authorize_resource :system_message, :through => [:user] - - def index - @system_messages = @system_messages.where(:created_at => Time.now - 6.hours .. Time.now) - end - - def show - end - - def new - @system_message = @user.system_messages.build - end - - def create - @system_message = @user.system_messages.build(params[:system_message]) - if @system_message.save - # Push the new message via AJAX to the browser. - # - # PrivatePub.publish_to("/users/#{@system_message.user.id}/system_messages", - # "$('#system_message').empty();$('#system_message').append('<span class=\"created_at\">#{(I18n.l @system_message.created_at, :format => :short )}</span> #{@system_message.content}');$('#system_message_display').fadeIn();" - # ) - - redirect_to user_system_message_path(@user, @system_message), :notice => t('system_messages.controller.successfuly_created') - else - render :new - end - end -end diff --git a/app/controllers/tenants_controller.rb b/app/controllers/tenants_controller.rb index 37874b2..b6a96b7 100644 --- a/app/controllers/tenants_controller.rb +++ b/app/controllers/tenants_controller.rb @@ -8,6 +8,7 @@ class TenantsController < ApplicationController def show @tenant = Tenant.find(params[:id]) @gateways = Gateway.order(:updated_at) + @backup_jobs = BackupJob.order(:finished_at).last(5) end def new @@ -27,17 +28,17 @@ class TenantsController < ApplicationController if @tenant.save # Become a member of this tenant. # - @tenant.tenant_memberships.create(:user_id => @current_user.id) + @tenant.tenant_memberships.create(:user_id => current_user.id) # Groups # admin_group = @tenant.user_groups.create(:name => t('gemeinschaft_setups.initial_setup.admin_group_name')) - admin_group.users << @current_user + admin_group.users << current_user user_group = @tenant.user_groups.create(:name => t('gemeinschaft_setups.initial_setup.user_group_name')) - user_group.users << @current_user + user_group.users << current_user - @current_user.update_attributes!(:current_tenant_id => @tenant.id) + current_user.update_attributes!(:current_tenant_id => @tenant.id) # Generate the internal_extensions # diff --git a/app/helpers/backup_jobs_helper.rb b/app/helpers/backup_jobs_helper.rb new file mode 100644 index 0000000..06d8b9b --- /dev/null +++ b/app/helpers/backup_jobs_helper.rb @@ -0,0 +1,2 @@ +module BackupJobsHelper +end diff --git a/app/helpers/intruders_helper.rb b/app/helpers/intruders_helper.rb new file mode 100644 index 0000000..7243cf3 --- /dev/null +++ b/app/helpers/intruders_helper.rb @@ -0,0 +1,2 @@ +module IntrudersHelper +end diff --git a/app/helpers/system_messages_helper.rb b/app/helpers/system_messages_helper.rb deleted file mode 100644 index fef2386..0000000 --- a/app/helpers/system_messages_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module SystemMessagesHelper -end diff --git a/app/models/ability.rb b/app/models/ability.rb index 0d13dab..4c0844c 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -56,14 +56,14 @@ class Ability can :read, PhoneBookEntry, :phone_book => { :id => user_group.phone_book_ids } end - # SystemMessages - # - cannot [:destroy, :edit, :update], SystemMessage - # A FacDocument can't be changed # cannot [:edit, :update], FaxDocument + # Backups can't be edited + # + cannot [:edit, :update], BackupJob + # Can manage GsNodes # can :manage, GsNode @@ -156,10 +156,6 @@ class Ability # can :manage, CallForward, :phone_number_id => user.phone_number_ids - # SystemMessages - # - can :read, SystemMessage, :user_id => user.id - # SoftkeyFunctions # can :read, SoftkeyFunction diff --git a/app/models/backup_job.rb b/app/models/backup_job.rb new file mode 100644 index 0000000..96574a7 --- /dev/null +++ b/app/models/backup_job.rb @@ -0,0 +1,51 @@ +class BackupJob < ActiveRecord::Base + attr_accessible :started_at, :finished_at, :state, :directory + + mount_uploader :backup_file, BackupFileUploader + + before_create :set_state_to_queued + after_create :initiate_backup + + def to_s + self.started_at.to_s + end + + private + def set_state_to_queued + self.state = 'queued' + self.started_at = Time.now + end + + def initiate_backup + self.delay.make_a_backup + end + + def make_a_backup + backup_directory = '/var/backups/GS5' + backup_name_prefix = 'GS5-backup-' + if self.finished_at.nil? && self.state == 'queued' + self.state = 'running' + self.save + original_directories = Dir.glob("#{backup_directory}/*") + system "backup perform --trigger GS5 --config_file #{Rails.root.join('config','backup.rb')}" + tmp_backup_directory = (Dir.glob("#{backup_directory}/*") - original_directories).first + if tmp_backup_directory.blank? + self.state = 'failed' + else + system "cd #{backup_directory} && 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") + + self.directory = File.basename(tmp_backup_directory) + + self.backup_file = File.open("#{backup_directory}/#{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz") + + self.finished_at = Time.now + self.state = 'successful' + end + self.save + end + end + +end diff --git a/app/models/call.rb b/app/models/call.rb index 57961ec..c0f0f08 100644 --- a/app/models/call.rb +++ b/app/models/call.rb @@ -1,36 +1,72 @@ class Call < ActiveRecord::Base - self.table_name = 'channels' + self.table_name = 'detailed_calls' self.primary_key = 'uuid' - # Makes sure that this is a readonly model. def readonly? return true end - - # Prevent objects from being destroyed - def before_destroy - raise ActiveRecord::ReadOnlyRecord - end - # Prevent objects from being deleted - def self.delete_all - raise ActiveRecord::ReadOnlyRecord + def destroy + return self.delete end - # Prevent objects from being deleted def delete - raise ActiveRecord::ReadOnlyRecord + require 'freeswitch_event' + return FreeswitchAPI.execute('uuid_kill', self.uuid, true); end def sip_account - auth_name = self.name.match('^.+[/:](.+)@.+$') - if auth_name && ! auth_name[1].blank? - return SipAccount.where(:auth_name => auth_name[1]).first + result = self.presence_id.match('^(.+)@(.+)$') + + if result && ! result[1].blank? and ! result[2].blank? + domain = SipDomain.where(:host => result[2]).first + if domain + return SipAccount.where(:auth_name => result[1], :sip_domain_id => domain.id).first + end end end - def kill + def sip_account_bleg + result = self.b_presence_id.match('^(.+)@(.+)$') + + if result && ! result[1].blank? and ! result[2].blank? + domain = SipDomain.where(:host => result[2]).first + if domain + return SipAccount.where(:auth_name => result[1], :sip_domain_id => domain.id).first + end + end + end + + def get_variable_from_uuid(channel_uuid, variable_name) + if channel_uuid.blank? + return nil + end + require 'freeswitch_event' - return FreeswitchAPI.execute('uuid_kill', self.uuid, true); + result = FreeswitchAPI.channel_variable_get(channel_uuid, variable_name); + + if result == '_undef_' + return nil + end + + return result + end + + def get_variable(variable_name) + return get_variable_from_uuid(self.uuid, variable_name); + end + + def get_variable_bleg(variable_name) + return get_variable_from_uuid(self.b_uuid, variable_name); + end + + def is_sip + return self.name.match('^sofia') != nil + end + + def is_caller + if (self.uuid == self.call_uuid) || self.call_uuid.blank? + true + end end end diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb index 8a8d1df..c668993 100644 --- a/app/models/call_forward.rb +++ b/app/models/call_forward.rb @@ -145,7 +145,7 @@ class CallForward < ActiveRecord::Base softkey_function_deactivated = SoftkeyFunction.find_by_name('deactivated') self.softkeys.each do |softkey| if softkey.softkey_function_id != softkey_function_deactivated.id - softkey.update_attributes(:call_forward_id => nil, :softkey_function_id => softkey_function_deactivated.id) + softkey.update_attributes(:softkeyable_id => nil, :softkeyable_type => nil, :softkey_function_id => softkey_function_deactivated.id) end end end diff --git a/app/models/call_route.rb b/app/models/call_route.rb index b4496ab..8bc811a 100644 --- a/app/models/call_route.rb +++ b/app/models/call_route.rb @@ -2,9 +2,9 @@ class CallRoute < ActiveRecord::Base # https://github.com/rails/strong_parameters include ActiveModel::ForbiddenAttributesProtection - ROUTING_TABLES = ['prerouting', 'outbound', 'inbound'] + ROUTING_TABLES = ['prerouting', 'outbound', 'inbound', 'dtmf'] - has_many :route_elements, :dependent => :destroy + has_many :route_elements, :dependent => :destroy, :order => :position validates :name, :presence => true @@ -239,6 +239,10 @@ class CallRoute < ActiveRecord::Base end end + def endpoint_str + "#{endpoint_type}=#{endpoint_id}" + end + def endpoint if self.endpoint_id.to_i > 0 begin diff --git a/app/models/gateway.rb b/app/models/gateway.rb index a8df41f..2f17b57 100644 --- a/app/models/gateway.rb +++ b/app/models/gateway.rb @@ -1,10 +1,12 @@ class Gateway < ActiveRecord::Base TECHNOLOGIES = ['sip', 'xmpp'] + GATEWAY_PREFIX = 'gateway' attr_accessible :name, :technology, :inbound, :outbound, :description has_many :gateway_settings, :dependent => :destroy has_many :gateway_parameters, :dependent => :destroy + has_many :call_routes, :as => :endpoint, :dependent => :nullify validates :name, :presence => true, @@ -21,6 +23,10 @@ class Gateway < ActiveRecord::Base name end + def identifier + "#{GATEWAY_PREFIX}#{self.id}" + end + private def downcase_technology self.technology = self.technology.downcase if !self.technology.blank? diff --git a/app/models/gateway_setting.rb b/app/models/gateway_setting.rb index e3eaadb..381dde5 100644 --- a/app/models/gateway_setting.rb +++ b/app/models/gateway_setting.rb @@ -10,6 +10,7 @@ class GatewaySetting < ActiveRecord::Base 'auth_source' => 'String', 'auth_pattern' => 'String', 'number_source' => 'String', + 'profile' => 'String', }, 'xmpp' => { 'server' => 'String', diff --git a/app/models/intruder.rb b/app/models/intruder.rb new file mode 100644 index 0000000..db14bf8 --- /dev/null +++ b/app/models/intruder.rb @@ -0,0 +1,37 @@ +class Intruder < ActiveRecord::Base + attr_accessible :list_type, :key, :points, :bans, :ban_last, :ban_end, :contact_ip, :contact_port, :contact_count, :contact_last, :contacts_per_second, :contacts_per_second_max, :user_agent, :to_user, :comment + + LIST_TYPES = ['blacklist', 'whitelist'] + + validates :list_type, + :presence => true, + :inclusion => { :in => LIST_TYPES } + + validates :key, + :presence => true, + :uniqueness => true + + validates :contact_ip, + :presence => true, + :uniqueness => true + + before_validation :set_key_if_empty + + + def whois + if ! self.contact_ip.blank? + begin + return Whois.whois(self.contact_ip) + rescue + return nil + end + end + end + + private + def set_key_if_empty + if self.key.blank? + self.key = self.contact_ip + end + end +end diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb index 444eb12..9ba1f8b 100644 --- a/app/models/sip_account.rb +++ b/app/models/sip_account.rb @@ -21,7 +21,7 @@ class SipAccount < ActiveRecord::Base belongs_to :tenant belongs_to :sip_domain - has_many :softkeys, :dependent => :destroy + has_many :softkeys, :dependent => :destroy, :order => :position has_many :voicemail_messages, :foreign_key => 'username', :primary_key => 'auth_name' diff --git a/app/models/softkey.rb b/app/models/softkey.rb index a709036..83c88ab 100644 --- a/app/models/softkey.rb +++ b/app/models/softkey.rb @@ -1,13 +1,11 @@ class Softkey < ActiveRecord::Base - attr_accessible :softkey_function_id, :number, :label, :call_forward_id, :uuid + attr_accessible :softkey_function_id, :number, :label, :uuid, :softkeyable_type, :softkeyable_id belongs_to :sip_account belongs_to :softkey_function - belongs_to :call_forward + belongs_to :softkeyable, :polymorphic => true - # Any CallForward BLF must have a valid softkey_call_forward_id. - # - validates_presence_of :call_forward_id, :if => Proc.new{ |softkey| self.softkey_function_id != nil && + validates_presence_of :softkeyable_id, :if => Proc.new{ |softkey| self.softkey_function_id != nil && self.softkey_function_id == SoftkeyFunction.find_by_name('call_forwarding').try(:id) } # These functions need a number to act. @@ -21,7 +19,6 @@ class Softkey < ActiveRecord::Base acts_as_list :scope => :sip_account before_validation :clean_up_and_leave_only_values_which_make_sense_for_the_current_softkey_function_id - after_validation :save_function_name_in_function, :if => Proc.new{ |softkey| self.call_forward_id.blank? } after_save :resync_phone after_destroy :resync_phone @@ -52,7 +49,7 @@ class Softkey < ActiveRecord::Base def to_s if (['call_forwarding'].include?(self.softkey_function.name)) - "#{self.call_forward}" + "#{self.softkeyable}" else if ['log_out', 'log_in'].include?(self.softkey_function.name) I18n.t("softkeys.functions.#{self.softkey_function.name}") @@ -78,21 +75,22 @@ class Softkey < ActiveRecord::Base end private - - def save_function_name_in_function - self.function = self.softkey_function.name - end - # Make sure that no number is set when there is no need for one. # And make sure that there is no CallForward connected when not needed. # def clean_up_and_leave_only_values_which_make_sense_for_the_current_softkey_function_id - if self.softkey_function_id != nil - if ['blf','speed_dial','dtmf','conference'].include?(self.softkey_function.name) - self.call_forward_id = nil - end - if ['call_forwarding'].include?(self.softkey_function.name) + if self.softkey_function_id != nil + case self.softkey_function.name + when 'blf' + self.softkeyable = PhoneNumber.where(:number => self.number, :phone_numberable_type => 'SipAccount').first.try(:phone_numberable) + when 'conference' + self.softkeyable = PhoneNumber.where(:number => self.number, :phone_numberable_type => 'Conference').first.try(:phone_numberable) + when 'call_forwarding' + self.softkeyable = CallForward.where(:id => self.softkeyable_id).first self.number = nil + else + self.softkeyable_id = nil + self.softkeyable_type = nil end end end diff --git a/app/models/system_message.rb b/app/models/system_message.rb deleted file mode 100644 index 0d9e862..0000000 --- a/app/models/system_message.rb +++ /dev/null @@ -1,7 +0,0 @@ -class SystemMessage < ActiveRecord::Base - attr_accessible :content - - belongs_to :user - - validates_presence_of :content -end diff --git a/app/uploaders/backup_file_uploader.rb b/app/uploaders/backup_file_uploader.rb new file mode 100644 index 0000000..8b126a9 --- /dev/null +++ b/app/uploaders/backup_file_uploader.rb @@ -0,0 +1,55 @@ +# encoding: utf-8 + +class BackupFileUploader < CarrierWave::Uploader::Base + + # Include RMagick or MiniMagick support: + # include CarrierWave::RMagick + # include CarrierWave::MiniMagick + + # Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility: + # include Sprockets::Helpers::RailsHelper + # include Sprockets::Helpers::IsolatedHelper + + # Choose what kind of storage to use for this uploader: + storage :file + # storage :fog + + # Override the directory where uploaded files will be stored. + # This is a sensible default for uploaders that are meant to be mounted: + def store_dir + "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" + end + + # Provide a default URL as a default if there hasn't been a file uploaded: + # def default_url + # # For Rails 3.1+ asset pipeline compatibility: + # # asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) + # + # "/images/fallback/" + [version_name, "default.png"].compact.join('_') + # end + + # Process files as they are uploaded: + # process :scale => [200, 300] + # + # def scale(width, height) + # # do something + # end + + # Create different versions of your uploaded files: + # version :thumb do + # process :scale => [50, 50] + # end + + # Add a white list of extensions which are allowed to be uploaded. + # For images you might use something like this: + # def extension_white_list + # %w(jpg jpeg gif png) + # end + + # Override the filename of the uploaded files: + # Avoid using model.id or version_name here, see uploader/store.rb for details. + # def filename + # "something.jpg" if original_filename + # end + +end diff --git a/app/views/backup_jobs/_form.html.haml b/app/views/backup_jobs/_form.html.haml new file mode 100644 index 0000000..e0adceb --- /dev/null +++ b/app/views/backup_jobs/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@backup_job) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('backup_jobs.form.submit')
\ No newline at end of file diff --git a/app/views/backup_jobs/_form_core.html.haml b/app/views/backup_jobs/_form_core.html.haml new file mode 100644 index 0000000..9d439c5 --- /dev/null +++ b/app/views/backup_jobs/_form_core.html.haml @@ -0,0 +1,5 @@ +.inputs + = f.input :started_at, :label => t('backup_jobs.form.started_at.label'), :hint => conditional_hint('backup_jobs.form.started_at.hint') + = f.input :finished_at, :label => t('backup_jobs.form.finished_at.label'), :hint => conditional_hint('backup_jobs.form.finished_at.hint') + = f.input :state, :label => t('backup_jobs.form.state.label'), :hint => conditional_hint('backup_jobs.form.state.hint') + = f.input :directory, :label => t('backup_jobs.form.directory.label'), :hint => conditional_hint('backup_jobs.form.directory.hint') diff --git a/app/views/backup_jobs/_index_core.html.haml b/app/views/backup_jobs/_index_core.html.haml new file mode 100644 index 0000000..0102546 --- /dev/null +++ b/app/views/backup_jobs/_index_core.html.haml @@ -0,0 +1,49 @@ +%table.table.table-striped + %tr + %th= t('backup_jobs.index.started_at') + %th + %span.hidden-phone + = t('backup_jobs.index.finished_at') + %th= t('backup_jobs.index.state') + %th + %span.hidden-phone + = t('backup_jobs.index.size_of_the_backup') + %th{:colspan => '2'} + + - for backup_job in backup_jobs + - if backup_job.state == 'queued' + - row_marker = 'warning' + - else + - if backup_job.state == 'failed' + - row_marker = 'error' + - else + - row_marker = '' + %tr{:class => row_marker} + - if backup_job.finished_at.blank? + %td{:colspan => '2'} + - if (Time.now - 1.day) > backup_job.started_at + = l backup_job.started_at, :format => :short + - else + - case I18n.locale + - when :de + = "vor #{time_ago_in_words(backup_job.started_at)}" + - when :en + = "#{time_ago_in_words(backup_job.started_at)} ago" + - else + = l backup_job.started_at, :format => :short + - else + %td + = l backup_job.started_at, :format => :short + %td + %span.hidden-phone + = l backup_job.finished_at, :format => :short + %td= backup_job.state + %td + %span.hidden-phone + - if backup_job.backup_file? + %a{:href => backup_job.backup_file.url} + %i{:class => 'icon-download'} + = number_to_human_size(backup_job.backup_file.size, :precision => 2) + - else + = '-' + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => backup_job} diff --git a/app/views/backup_jobs/edit.html.haml b/app/views/backup_jobs/edit.html.haml new file mode 100644 index 0000000..7892edb --- /dev/null +++ b/app/views/backup_jobs/edit.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("backup_jobs.edit.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/backup_jobs/index.html.haml b/app/views/backup_jobs/index.html.haml new file mode 100644 index 0000000..0bb4747 --- /dev/null +++ b/app/views/backup_jobs/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("backup_jobs.index.page_title") + +- if @backup_jobs && @backup_jobs.count > 0 + = render "index_core", :backup_jobs => @backup_jobs + += render :partial => 'shared/create_link', :locals => {:child_class => BackupJob}
\ No newline at end of file diff --git a/app/views/backup_jobs/new.html.haml b/app/views/backup_jobs/new.html.haml new file mode 100644 index 0000000..65efd4f --- /dev/null +++ b/app/views/backup_jobs/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("backup_jobs.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/backup_jobs/show.html.haml b/app/views/backup_jobs/show.html.haml new file mode 100644 index 0000000..6fcb1dc --- /dev/null +++ b/app/views/backup_jobs/show.html.haml @@ -0,0 +1,22 @@ +- content_for :title, t("backup_jobs.show.page_title") + +%p + %strong= t('backup_jobs.show.started_at') + ":" + = @backup_job.started_at +%p + %strong= t('backup_jobs.show.finished_at') + ":" + = @backup_job.finished_at +%p + %strong= t('backup_jobs.show.state') + ":" + = @backup_job.state +%p + %strong= t('backup_jobs.show.directory') + ":" + = @backup_job.directory +%p + %strong= t('backup_jobs.show.size_of_the_backup') + ":" + - if @backup_job.backup_file? + %a{:href => backup_job.backup_file.url} + %i{:class => 'icon-download'} + = number_to_human_size(backup_job.backup_file.size, :precision => 2) + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @backup_job }
\ No newline at end of file diff --git a/app/views/call_histories/_index_core.html.haml b/app/views/call_histories/_index_core.html.haml index 4ca340d..8bbf761 100644 --- a/app/views/call_histories/_index_core.html.haml +++ b/app/views/call_histories/_index_core.html.haml @@ -22,7 +22,7 @@ - phone_book_entry = call_history.phone_book_entry_by_number(call_history.display_number) %tr{:id => "call_history_id_#{call_history.id}_tr", :class => (call_history.duration.blank? ? 'warning' : '')} %td - = l call_history.start_stamp, :format => :date_only + = l call_history.start_stamp, :format => :short %td = l call_history.start_stamp, :format => :short %td diff --git a/app/views/call_routes/_form_core.html.haml b/app/views/call_routes/_form_core.html.haml index b64d660..926c985 100644 --- a/app/views/call_routes/_form_core.html.haml +++ b/app/views/call_routes/_form_core.html.haml @@ -1,5 +1,5 @@ .inputs = f.input :routing_table, :collection => CallRoute::ROUTING_TABLES, :label => t('call_routes.form.table.label'), :hint => conditional_hint('call_routes.form.table.hint'), :include_blank => false, :autofocus => true = f.input :name, :label => t('call_routes.form.name.label'), :hint => conditional_hint('call_routes.form.name.hint') - = f.input :endpoint_type, :label => t('call_routes.form.endpoint_type.label'), :hint => conditional_hint('call_routes.form.endpoint_type.hint') - = f.input :endpoint_id, :label => t('call_routes.form.endpoint_id.label'), :hint => conditional_hint('call_routes.form.endpoint_id.hint') + = f.input :endpoint_str, :collection => @endpoints, :label => t('call_routes.form.endpoint.label'), :hint => conditional_hint('call_routes.form.endpoint.hint'), :include_blank => false + = f.input :position, :label => t('call_routes.form.position.label'), :hint => conditional_hint('call_routes.form.position.hint')
\ No newline at end of file diff --git a/app/views/call_routes/_index_core.html.haml b/app/views/call_routes/_index_core.html.haml index f0acebb..a62a9c4 100644 --- a/app/views/call_routes/_index_core.html.haml +++ b/app/views/call_routes/_index_core.html.haml @@ -1,15 +1,19 @@ -- cache(['call_routes_table', call_routes.count, call_routes.reorder(:updated_at).last]) do +- cache(['call_routes_table', I18n.locale, call_routes.count, call_routes.reorder(:updated_at).last]) do %table.table.table-striped %thead %tr + %th %th= t('call_routes.index.name') %th= t('route_elements.index.pattern') %th= t('call_routes.index.endpoint') - %tbody + %tbody{ :class => "call_routes", :id => "call_routes_#{routing_table}", :'data-update-url' => sort_call_routes_url} - for call_route in call_routes - - cache(['call_route_single_table_row', call_route, call_routes.count]) do - %tr + - cache(['call_route_single_table_row', I18n.locale, call_route]) do + = content_tag_for :tr, call_route do + %td + %span.handle + %i.icon-resize-vertical %td= call_route.name %td - if call_route.route_elements.any? diff --git a/app/views/call_routes/index.html.haml b/app/views/call_routes/index.html.haml index 488e1c7..0108322 100644 --- a/app/views/call_routes/index.html.haml +++ b/app/views/call_routes/index.html.haml @@ -1,11 +1,8 @@ - content_for :title, t("call_routes.index.page_title") -- if @call_routes && @call_routes.count > 0 - %table.table.table-striped - - @routing_tables.each do |routing_table| - %tr - %td{:colspan => 3} - %h3= routing_table - = render "index_core", :call_routes => @call_routes.where(:routing_table => routing_table) +- if @call_routes && @call_routes.any? + - @routing_tables.each do |routing_table| + %h3= routing_table + = render "index_core", :call_routes => @call_routes.where(:routing_table => routing_table), :routing_table => routing_table = render :partial => 'shared/create_link', :locals => {:child_class => CallRoute} diff --git a/app/views/call_routes/show.html.haml b/app/views/call_routes/show.html.haml index 09daf53..7c695c8 100644 --- a/app/views/call_routes/show.html.haml +++ b/app/views/call_routes/show.html.haml @@ -1,23 +1,33 @@ - content_for :title, t("call_routes.show.page_title") -%p - %strong= t('call_routes.show.table') + ":" - = @call_route.routing_table -%p - %strong= t('call_routes.show.name') + ":" - = @call_route.name -%p - %strong= t('call_routes.show.endpoint') + ":" - - endpoint = @call_route.endpoint - - if endpoint - = endpoint - - else - = @call_route.endpoint_type +.row + .span5 + %table.table.table-striped + %tr + %td + %strong= t('call_routes.show.table') + ":" + %td + = @call_route.routing_table + %tr + %td + %strong= t('call_routes.show.name') + ":" + %td + = @call_route.name + %tr + %td + %strong= t('call_routes.show.endpoint') + ":" + %td + - if @call_route.endpoint.blank? + = @call_route.endpoint_type + - else + = @call_route.endpoint -= render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @call_route } + = render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @call_route } -%h3= t('route_elements.index.page_title') -- if @call_route.route_elements && @call_route.route_elements.count > 0 - = render "route_elements/index_core", :route_elements => @call_route.route_elements +.row + .span12 + %h3= t('route_elements.index.page_title') + - if @call_route.route_elements && @call_route.route_elements.count > 0 + = render "route_elements/index_core", :route_elements => @call_route.route_elements -= render :partial => 'shared/create_link', :locals => { :parent => @call_route, :child_class => RouteElement } + = render :partial => 'shared/create_link', :locals => { :parent => @call_route, :child_class => RouteElement } diff --git a/app/views/call_routes/show.xml.haml b/app/views/call_routes/show.xml.haml new file mode 100644 index 0000000..5800816 --- /dev/null +++ b/app/views/call_routes/show.xml.haml @@ -0,0 +1,5 @@ +!!! XML +%call_route{ :name => @call_route.name, :routing_table => @call_route.routing_table, :position => @call_route.position, :endpoint => @call_route.endpoint, :endpoint_type => @call_route.endpoint_type } + %route_elements{ :count => @call_route.route_elements.count } + - @call_route.route_elements.each do |route_element| + %route_element{ :var_in => route_element.var_in, :var_out => route_element.var_out, :pattern => route_element.pattern, :replacement => route_element.replacement, :action => route_element.action, :mandatory => route_element.mandatory.to_s, :position => route_element.position } diff --git a/app/views/call_routes/show_variables.html.haml b/app/views/call_routes/show_variables.html.haml new file mode 100644 index 0000000..4bec39d --- /dev/null +++ b/app/views/call_routes/show_variables.html.haml @@ -0,0 +1,13 @@ +%h3= 'Channel Variables' + +%table.table.table-striped + %thead + %tr + %th= 'Variable' + %th= 'Value' + + %tbody{ :id => "show_variables" } + - @channel_variables.each do |key, value| + %tr + %td= key + %td= value.gsub(/\n/, '<br/>').html_safe diff --git a/app/views/config_snom/show.xml.haml b/app/views/config_snom/show.xml.haml index 5f53802..33204dc 100644 --- a/app/views/config_snom/show.xml.haml +++ b/app/views/config_snom/show.xml.haml @@ -40,7 +40,11 @@ %mwi_notification{:perm => 'RW'}= 'silent' %mwi_dialtone{:perm => 'RW'}= 'normal' %prefer_saved_over_received_photo{:perm => 'RW'}= 'off' - %no_dnd{:perm => 'RW'}= 'on' + %no_dnd{:perm => 'RW'}= 'off' + %transfer_on_hangup{:perm => 'RW'}= 'on' + %transfer_on_hangup_non_pots{:perm => 'RW'}= 'off' + %call_join_xfer{:perm => 'RW'}= 'on' + %conf_hangup{:perm => 'RW'}= 'on' %logon_wizard{:perm => 'RW'}= 'off' %disable_deflection{:perm => 'RW'}= 'off' %csta_control{:perm => 'RW'}= 'on' @@ -117,7 +121,7 @@ %user_realname{:idx => index, :perm => 'R'}= sip_account[:realname] %user_idle_text{:idx => index, :perm => 'R'}= sip_account[:idle_text] %user_mailbox{:idx => index, :perm => 'R'}= sip_account[:mailbox] - %user_expiry{:idx => index, :perm => 'R'}= '' + %user_expiry{:idx => index, :perm => 'R'}= sip_account[:expiry] %user_server_type{:idx => index, :perm => 'R'}= 'default' %user_send_local_name{:idx => index, :perm => 'RW'}= 'on' %user_dtmf_info{:idx => index, :perm => 'RW'}= 'off' diff --git a/app/views/fax_accounts/_index_core.html.haml b/app/views/fax_accounts/_index_core.html.haml index d694f8f..846cda8 100644 --- a/app/views/fax_accounts/_index_core.html.haml +++ b/app/views/fax_accounts/_index_core.html.haml @@ -39,8 +39,8 @@ = time_ago_in_words(fax_account.fax_documents.order(:updated_at).last.updated_at) %td - if can?(:new, FaxDocument, :fax_account_id => fax_account.id) - %a.btn.btn-mini.btn-primary{:href => new_fax_account_fax_document_path(fax_account) } - %i.icon-print.icon-white + %a.btn.btn-small{:href => new_fax_account_fax_document_path(fax_account) } + %i.icon-print %span.hidden-phone =t('fax_accounts.index.send_a_fax') diff --git a/app/views/fax_accounts/show.html.haml b/app/views/fax_accounts/show.html.haml index 1a32121..454ebee 100644 --- a/app/views/fax_accounts/show.html.haml +++ b/app/views/fax_accounts/show.html.haml @@ -12,7 +12,11 @@ = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @parent, :child => @fax_account } -= render :partial => 'shared/create_link', :locals => { :parent => @fax_account, :child_class => FaxDocument } +%p + %a.btn.btn-small{:href => new_fax_account_fax_document_path(@fax_account) } + %i.icon-print + %span.hidden-phone + =t('fax_accounts.index.send_a_fax') %h2= t('phone_numbers.index.page_title') - if @fax_account.phone_numbers.count > 0 diff --git a/app/views/gateways/show.xml.haml b/app/views/gateways/show.xml.haml new file mode 100644 index 0000000..e0ff21a --- /dev/null +++ b/app/views/gateways/show.xml.haml @@ -0,0 +1,17 @@ +!!! XML +%gateway{ :identifier => @gateway.identifier, :name => @gateway.name, :technology => @gateway.technology, :inbound => @gateway.inbound.to_s, :outbound => @gateway.outbound.to_s, :description => @gateway.description } + + %gateway_settings{ :count => @gateway.gateway_settings.count } + - @gateway.gateway_settings.each do |setting| + %setting{ :name => setting.name, :value => setting.value, :class_type => setting.class_type, :description => setting.description } + + %gateway_parameters{ :count => @gateway.gateway_parameters.count } + - @gateway.gateway_parameters.each do |parameter| + %parameter{ :name => parameter.name, :value => parameter.value, :class_type => parameter.class_type, :description => parameter.description } + + %call_routes{ :count => @gateway.call_routes.count } + - @gateway.call_routes.each do |call_route| + %call_route{ :name => call_route.name, :routing_table => call_route.routing_table, :position => call_route.position } + %route_elements{ :count => call_route.route_elements.count } + - call_route.route_elements.each do |route_element| + %route_element{ :var_in => route_element.var_in, :var_out => route_element.var_out, :pattern => route_element.pattern, :replacement => route_element.replacement, :action => route_element.action, :mandatory => route_element.mandatory.to_s, :position => route_element.position } diff --git a/app/views/gemeinschaft_setups/new.de.html.haml b/app/views/gemeinschaft_setups/new.de.html.haml index cf1f207..f977291 100644 --- a/app/views/gemeinschaft_setups/new.de.html.haml +++ b/app/views/gemeinschaft_setups/new.de.html.haml @@ -14,6 +14,7 @@ = f.association :country, :label => t('gemeinschaft_setups.form.country_id.label'), :hint => conditional_hint('gemeinschaft_setups.form.country_id.hint'), :include_blank => false = f.association :language, :label => t('gemeinschaft_setups.form.language_id.label'), :hint => conditional_hint('gemeinschaft_setups.form.language_id.hint'), :include_blank => false = f.input :default_area_code, :label => t('gemeinschaft_setups.form.default_area_code.label'), :hint => conditional_hint('gemeinschaft_setups.form.default_area_code.hint') + = f.input :trunk_access_code, :label => t('gemeinschaft_setups.form.trunk_access_code.label'), :hint => conditional_hint('gemeinschaft_setups.form.trunk_access_code.hint') = f.input :default_company_name, :label => t('gemeinschaft_setups.form.default_company_name.label'), :hint => conditional_hint('gemeinschaft_setups.form.default_company_name.hint') diff --git a/app/views/gemeinschaft_setups/new.html.haml b/app/views/gemeinschaft_setups/new.html.haml index 5e2434e..44d9c5b 100644 --- a/app/views/gemeinschaft_setups/new.html.haml +++ b/app/views/gemeinschaft_setups/new.html.haml @@ -14,6 +14,7 @@ = f.association :country, :label => t('gemeinschaft_setups.form.country_id.label'), :hint => conditional_hint('gemeinschaft_setups.form.country_id.hint'), :include_blank => false = f.association :language, :label => t('gemeinschaft_setups.form.language_id.label'), :hint => conditional_hint('gemeinschaft_setups.form.language_id.hint'), :include_blank => false = f.input :default_area_code, :label => t('gemeinschaft_setups.form.default_area_code.label'), :hint => conditional_hint('gemeinschaft_setups.form.default_area_code.hint') + = f.input :trunk_access_code, :label => t('gemeinschaft_setups.form.trunk_access_code.label'), :hint => conditional_hint('gemeinschaft_setups.form.trunk_access_code.hint') = f.input :default_company_name, :label => t('gemeinschaft_setups.form.default_company_name.label'), :hint => conditional_hint('gemeinschaft_setups.form.default_company_name.hint') diff --git a/app/views/gs_nodes/sync.xml.haml b/app/views/gs_nodes/sync.xml.haml index 0f097f8..a2fa71a 100644 --- a/app/views/gs_nodes/sync.xml.haml +++ b/app/views/gs_nodes/sync.xml.haml @@ -60,7 +60,7 @@ - if !@softkeys.blank? %softkeys - @softkeys.each do |softkey| - %softkey{ :uuid => softkey.uuid, :function => softkey.softkey_function.try(:name), :number => softkey.number, :label => softkey.label, :position => softkey.position, :created_at => softkey.created_at, :updated_at => softkey.updated_at, :sip_account_uuid => softkey.sip_account.try(:uuid), :call_forward_uuid => softkey.call_forward.try(:uuid) } + %softkey{ :uuid => softkey.uuid, :function => softkey.softkey_function.try(:name), :number => softkey.number, :label => softkey.label, :position => softkey.position, :created_at => softkey.created_at, :updated_at => softkey.updated_at, :sip_account_uuid => softkey.sip_account.try(:uuid), :softkeyable_uuid => softkey.softkeyable.try(:uuid), :softkeyable_type => softkey.softkeyable_type) } - if !@ringtones.blank? %ringtones diff --git a/app/views/gs_parameters/_index_core.html.haml b/app/views/gs_parameters/_index_core.html.haml index 11d60db..2105126 100644 --- a/app/views/gs_parameters/_index_core.html.haml +++ b/app/views/gs_parameters/_index_core.html.haml @@ -1,6 +1,9 @@ -- cache(['gs_parameters_table_section', gs_parameters.first.section, gs_parameters.reorder(:updated_at).last, gs_parameters.pluck(:id)]) do +- cache(['gs_parameter_sub_table', I18n.locale, gs_parameters.count, gs_parameters.reorder(:updated_at).first, gs_parameters.reorder(:updated_at).last]) do %thead %tr + %th + %span.hidden-phone + = t('gs_parameters.index.entity') %th= t('gs_parameters.index.name') - if !@sections %th= t('gs_parameters.index.section') @@ -8,9 +11,16 @@ %tbody - for gs_parameter in gs_parameters - - cache(['gs_parameters_table_single_row', gs_parameter]) do + - cache(['gs_parameters_table_single_row', I18n.locale, gs_parameter]) do %tr %td + - if gs_parameter.entity.blank? + %span.hidden-phone + = '-' + - else + %span.hidden-phone + = truncate(gs_parameter.entity, :length => GsParameter.get('DESKTOP_MAX_STRING_LENGTH')) + %td %span.hidden-phone = truncate(gs_parameter.name, :length => GsParameter.get('DESKTOP_MAX_STRING_LENGTH')) %span.visible-phone diff --git a/app/views/gs_parameters/index.html.haml b/app/views/gs_parameters/index.html.haml index 1189a45..8df2bb3 100644 --- a/app/views/gs_parameters/index.html.haml +++ b/app/views/gs_parameters/index.html.haml @@ -1,13 +1,11 @@ - content_for :title, t("gs_parameters.index.page_title") -- if @gs_parameters && @gs_parameters.count > 0 - - cache(['gs_parameters_table', I18n.locale, @gs_parameters_unordered.reorder(:updated_at).last, @gs_parameters_unordered.count]) do +- cache(['gs_parameter_all_tables', I18n.locale, @gs_parameters.count, @gs_parameters.reorder(:updated_at).first, @gs_parameters.reorder(:updated_at).last]) do + - if @gs_parameters && @gs_parameters.count > 0 - if @sections - %table.table.table-striped - - @sections.each do |section| - %tr - %td{:colspan => 3} - %h3= section + - @sections.each do |section| + %h3= section + %table.table.table-striped -# Template Dependency: gs_parameters/_index_core = render "index_core", :gs_parameters => @gs_parameters.where(:section => section) - else diff --git a/app/views/intruders/_form.html.haml b/app/views/intruders/_form.html.haml new file mode 100644 index 0000000..26aab1c --- /dev/null +++ b/app/views/intruders/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@intruder) do |f| + = f.error_notification + + = render "form_core", :f => f + + .actions + = f.button :submit, conditional_t('intruders.form.submit')
\ No newline at end of file diff --git a/app/views/intruders/_form_core.html.haml b/app/views/intruders/_form_core.html.haml new file mode 100644 index 0000000..780d8cd --- /dev/null +++ b/app/views/intruders/_form_core.html.haml @@ -0,0 +1,5 @@ +.inputs + = f.input :list_type, :collection => Intruder::LIST_TYPES, :label => t('intruders.form.list_type.label'), :hint => conditional_hint('intruders.form.list_type.hint'), :include_blank => false + = f.input :contact_ip, :label => t('intruders.form.contact_ip.label'), :hint => conditional_hint('intruders.form.contact_ip.hint') + = f.input :ban_end, :label => t('intruders.form.ban_end.label'), :hint => conditional_hint('intruders.form.ban_end.hint') + = f.input :comment, :label => t('intruders.form.comment.label'), :hint => conditional_hint('intruders.form.comment.hint') diff --git a/app/views/intruders/_index_core.html.haml b/app/views/intruders/_index_core.html.haml new file mode 100644 index 0000000..0070c4d --- /dev/null +++ b/app/views/intruders/_index_core.html.haml @@ -0,0 +1,37 @@ +%table.table.table-striped + %tr + %th= t('intruders.index.list_type') + %th= t('intruders.index.key') + %th= t('intruders.index.points') + %th= t('intruders.index.bans') + %th= t('intruders.index.ban_last') + %th= t('intruders.index.ban_end') + %th= t('intruders.index.contact_ip') + %th= t('intruders.index.contact_port') + %th= t('intruders.index.contact_count') + %th= t('intruders.index.contact_last') + %th= t('intruders.index.contacts_per_second') + %th= t('intruders.index.contacts_per_second_max') + %th= t('intruders.index.user_agent') + %th= t('intruders.index.to_user') + %th= t('intruders.index.comment') + + + - for intruder in intruders + %tr + %td= intruder.list_type + %td= intruder.key + %td= intruder.points + %td= intruder.bans + %td= intruder.ban_last + %td= intruder.ban_end + %td= intruder.contact_ip + %td= intruder.contact_port + %td= intruder.contact_count + %td= intruder.contact_last + %td= intruder.contacts_per_second + %td= intruder.contacts_per_second_max + %td= intruder.user_agent + %td= intruder.to_user + %td= intruder.comment + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => intruder}
\ No newline at end of file diff --git a/app/views/intruders/edit.html.haml b/app/views/intruders/edit.html.haml new file mode 100644 index 0000000..1b5a31b --- /dev/null +++ b/app/views/intruders/edit.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("intruders.edit.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/intruders/index.html.haml b/app/views/intruders/index.html.haml new file mode 100644 index 0000000..72b8882 --- /dev/null +++ b/app/views/intruders/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("intruders.index.page_title") + +- if @intruders && @intruders.count > 0 + = render "index_core", :intruders => @intruders + += render :partial => 'shared/create_link', :locals => {:child_class => Intruder}
\ No newline at end of file diff --git a/app/views/intruders/new.html.haml b/app/views/intruders/new.html.haml new file mode 100644 index 0000000..a24b55f --- /dev/null +++ b/app/views/intruders/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("intruders.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/intruders/show.html.haml b/app/views/intruders/show.html.haml new file mode 100644 index 0000000..4941e89 --- /dev/null +++ b/app/views/intruders/show.html.haml @@ -0,0 +1,52 @@ +- content_for :title, t("intruders.show.page_title") + +%p + %strong= t('intruders.show.list_type') + ":" + = @intruder.list_type +%p + %strong= t('intruders.show.key') + ":" + = @intruder.key +%p + %strong= t('intruders.show.points') + ":" + = @intruder.points +%p + %strong= t('intruders.show.bans') + ":" + = @intruder.bans +%p + %strong= t('intruders.show.ban_last') + ":" + = @intruder.ban_last +%p + %strong= t('intruders.show.ban_end') + ":" + = @intruder.ban_end +%p + %strong= t('intruders.show.contact_ip') + ":" + = @intruder.contact_ip +%p + %strong= t('intruders.show.contact_port') + ":" + = @intruder.contact_port +%p + %strong= t('intruders.show.contact_count') + ":" + = @intruder.contact_count +%p + %strong= t('intruders.show.contact_last') + ":" + = @intruder.contact_last +%p + %strong= t('intruders.show.contacts_per_second') + ":" + = @intruder.contacts_per_second +%p + %strong= t('intruders.show.contacts_per_second_max') + ":" + = @intruder.contacts_per_second_max +%p + %strong= t('intruders.show.user_agent') + ":" + = @intruder.user_agent +%p + %strong= t('intruders.show.to_user') + ":" + = @intruder.to_user +%p + %strong= t('intruders.show.comment') + ":" + = @intruder.comment + +%p + %pre= @intruder.whois + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @intruder } diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index 97bf483..2703844 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -14,6 +14,6 @@ %li = link_to 'GS5 Google Group', "https://groups.google.com/group/gs5-users/" %li - =link_to t('misc.send_a_bugreport'), URI::escape("https://github.com/amooma/GS5/issues/new?title=Bugreport&body=URL which triggered the bugreport is: #{request.fullpath}\nGS5 buildname: #{(GsParameter.get('GEMEINSCHAFT_BUILDNAME').blank? ? 'unknown' : GsParameter.get('GEMEINSCHAFT_BUILDNAME'))}\n\nPlease provide your bugreport below this line and update the title of this issue to a more specific one.") + =link_to t('misc.send_a_bugreport'), URI::escape("https://github.com/amooma/GS5/issues/new?title=Bugreport&body=URL which triggered the bugreport is: #{request.fullpath}\nGS5 buildname: #{(GsParameter.get('GEMEINSCHAFT_BUILDNAME').blank? ? 'unknown' : GsParameter.get('GEMEINSCHAFT_BUILDNAME'))} (#{GsParameter.get('GEMEINSCHAFT_VERSION')})\n\nPlease provide your bugreport below this line and update the title of this issue to a more specific one.") %li{:class => 'pull-right'} - = link_to 'brought to you by AMOOMA GmbH', 'http://amooma.de'
\ No newline at end of file + = link_to '© AMOOMA GmbH', 'http://amooma.de'
\ No newline at end of file diff --git a/app/views/layouts/_navbar.html.haml b/app/views/layouts/_navbar.html.haml index c2d9946..7084090 100644 --- a/app/views/layouts/_navbar.html.haml +++ b/app/views/layouts/_navbar.html.haml @@ -14,18 +14,16 @@ - if current_user && GemeinschaftSetup.any? && current_user.admin? - if current_page?(page_help_path) %li.active - =link_to 'Admin-Doku', page_help_path + =link_to t('navigation.admin_docu'), page_help_path - else %li - =link_to 'Admin-Doku', page_help_path + =link_to t('navigation.admin_docu'), page_help_path - if current_user && current_user.sip_accounts.any? %li %a{:href => sip_account_call_histories_path(current_user.sip_accounts.first)} - %i.icon-list-alt.icon-white =t("call_histories.index.page_title") %li %a{:href => sip_account_voicemail_messages_path(current_user.sip_accounts.first)} - %i.icon-volume-up.icon-white =t("voicemail_messages.index.page_title") - if current_user @@ -48,7 +46,8 @@ %a.navbar-link{:href => tenant_user_path(current_user.current_tenant, current_user)} = current_user - %li - %a.navbar-link{:href => log_out_path} - %i.icon-off.icon-white + - if single_sign_on_system? == false + %li + %a.navbar-link{:href => log_out_path} + %i.icon-off.icon-white diff --git a/app/views/phone_numbers/_form_core.html.haml b/app/views/phone_numbers/_form_core.html.haml index a1ce1f3..a0a69db 100644 --- a/app/views/phone_numbers/_form_core.html.haml +++ b/app/views/phone_numbers/_form_core.html.haml @@ -4,7 +4,7 @@ = f.input :name, :collection => ['Office', 'Home', 'Mobile', 'Fax'], :include_blank => false, :label => t('phone_numbers.form.name.label'), :hint => conditional_hint('phone_numbers.form.name.hint') = f.input :number, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint'), :autofocus => true - else - - if @callthrough || @hunt_group_member || @access_authorization || @current_user.current_tenant.array_of_available_internal_extensions_and_dids.count == 0 || @current_user.current_tenant.array_of_available_internal_extensions_and_dids.count > 250 + - if @callthrough || @hunt_group_member || @access_authorization || current_user.current_tenant.array_of_available_internal_extensions_and_dids.count == 0 || current_user.current_tenant.array_of_available_internal_extensions_and_dids.count > 250 = f.input :number, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint'), :autofocus => true - else - = f.input :number, :collection => @current_user.current_tenant.array_of_available_internal_extensions_and_dids, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint'), :include_blank => false, :autofocus => true + = f.input :number, :collection => current_user.current_tenant.array_of_available_internal_extensions_and_dids, :label => t('phone_numbers.form.number.label'), :hint => conditional_hint('phone_numbers.form.number.hint'), :include_blank => false, :autofocus => true diff --git a/app/views/phone_numbers/_index_core.html.haml b/app/views/phone_numbers/_index_core.html.haml index 80a1608..85982da 100644 --- a/app/views/phone_numbers/_index_core.html.haml +++ b/app/views/phone_numbers/_index_core.html.haml @@ -1,13 +1,18 @@ %table.table.table-striped %thead %tr + %th - if phone_numbers.count > 1 && phone_numbers.first.phone_numberable_type == 'PhoneBookEntry' %th= t('phone_numbers.index.name') %th= t('phone_numbers.index.number') - %tbody + %tbody{ :id => "phone_numbers", :'data-update-url' => sort_phone_numbers_url} - for phone_number in phone_numbers.order(:position) - %tr + = content_tag_for :tr, phone_number do + %td + - if phone_numbers.count > 1 + %span.handle + %i.icon-resize-vertical - if phone_number.phone_numberable_type == 'PhoneBookEntry' %td= phone_number.name %td= phone_number diff --git a/app/views/phones/_form_core.html.haml b/app/views/phones/_form_core.html.haml index 17b9ca8..31f3c24 100644 --- a/app/views/phones/_form_core.html.haml +++ b/app/views/phones/_form_core.html.haml @@ -11,5 +11,5 @@ - if defined? GsParameter.get('NIGHTLY_REBOOT_OF_PHONES') && GsParameter.get('NIGHTLY_REBOOT_OF_PHONES') == true = f.input :nightly_reboot, :label => t('phones.form.nightly_reboot.label'), :hint => conditional_hint('phones.form.nightly_reboot.hint') - - if !GsParameter.get('PROVISIONING_KEY_LENGTH').nil? && GsParameter.get('PROVISIONING_KEY_LENGTH') > 0 + - if GsParameter.get('PROVISIONING_KEY_LENGTH') == 0 = f.input :provisioning_key_active, :label => t('phones.form.provisioning_key_active.label'), :hint => conditional_hint('phones.form.provisioning_key_active.hint') diff --git a/app/views/phones/show.html.haml b/app/views/phones/show.html.haml index 86ac380..e9b8b21 100644 --- a/app/views/phones/show.html.haml +++ b/app/views/phones/show.html.haml @@ -34,7 +34,7 @@ %td = @phone.nightly_reboot == true ? t('simple_form.yes') : t('simple_form.no') - - if !GsParameter.get('PROVISIONING_KEY_LENGTH').nil? && GsParameter.get('PROVISIONING_KEY_LENGTH') > 0 + - if GsParameter.get('PROVISIONING_KEY_LENGTH') == 0 %tr %td %strong= t('phones.show.provisioning_key_active') + ":" diff --git a/app/views/route_elements/_index_core.html.haml b/app/views/route_elements/_index_core.html.haml index 37c0656..b7d2bc1 100644 --- a/app/views/route_elements/_index_core.html.haml +++ b/app/views/route_elements/_index_core.html.haml @@ -1,20 +1,46 @@ %table.table.table-striped %thead %tr - %th= t('route_elements.index.var_in') - %th= t('route_elements.index.var_out') + - if route_elements.count > 1 + %th + %th + %span.hidden-phone + = t('route_elements.index.var_in') + %th + %span.hidden-phone + = t('route_elements.index.var_out') %th= t('route_elements.index.pattern') - %th= t('route_elements.index.replacement') - %th= t('route_elements.index.action') - %th= t('route_elements.index.mandatory') + %th + %span.hidden-phone + = t('route_elements.index.replacement') + %th + %span.hidden-phone + = t('route_elements.index.action') + %th + %span.hidden-phone + = t('route_elements.index.mandatory') - %tbody + %tbody{ :id => "route_elements", :'data-update-url' => sort_call_route_route_elements_url(route_elements.first.call_route)} - for route_element in route_elements - %tr - %td= route_element.var_in - %td= route_element.var_out + = content_tag_for :tr, route_element do + - if route_elements.count > 1 + %td + %span.handle + %i.icon-resize-vertical + %td + %span.hidden-phone + = route_element.var_in + %td + %span.hidden-phone + = route_element.var_out %td= route_element.pattern - %td= route_element.replacement - %td= route_element.action - %td= route_element.mandatory + %td + %span.hidden-phone + = route_element.replacement + %td + %span.hidden-phone + = route_element.action + %td + %span.hidden-phone + = route_element.mandatory =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => @call_route, :child => route_element}
\ No newline at end of file diff --git a/app/views/route_elements/show.html.haml b/app/views/route_elements/show.html.haml index 808f2a0..937df5e 100644 --- a/app/views/route_elements/show.html.haml +++ b/app/views/route_elements/show.html.haml @@ -1,22 +1,37 @@ - content_for :title, t("route_elements.show.page_title") -%p - %strong= t('route_elements.show.var_in') + ":" - = @route_element.var_in -%p - %strong= t('route_elements.show.var_out') + ":" - = @route_element.var_out -%p - %strong= t('route_elements.show.pattern') + ":" - = @route_element.pattern -%p - %strong= t('route_elements.show.replacement') + ":" - = @route_element.replacement -%p - %strong= t('route_elements.show.action') + ":" - = @route_element.action -%p - %strong= t('route_elements.show.mandatory') + ":" - = @route_element.mandatory +.row + .span6 + %table.table.table-striped + %tr + %td + %strong= t('route_elements.show.var_in') + ":" + %td + = @route_element.var_in + %tr + %td + %strong= t('route_elements.show.var_out') + ":" + %td + = @route_element.var_out + %tr + %td + %strong= t('route_elements.show.pattern') + ":" + %td + = @route_element.pattern + %tr + %td + %strong= t('route_elements.show.replacement') + ":" + %td + = @route_element.replacement + %tr + %td + %strong= t('route_elements.show.action') + ":" + %td + = @route_element.action + %tr + %td + %strong= t('route_elements.show.mandatory') + ":" + %td + = @route_element.mandatory = render :partial => 'shared/show_edit_destroy_part', :locals => {:parent => @call_route, :child => @route_element }
\ No newline at end of file diff --git a/app/views/shared/_index_view_edit_destroy_part.html.haml b/app/views/shared/_index_view_edit_destroy_part.html.haml index 6bb1e7b..d396460 100644 --- a/app/views/shared/_index_view_edit_destroy_part.html.haml +++ b/app/views/shared/_index_view_edit_destroy_part.html.haml @@ -4,17 +4,20 @@ - if can? :show, child %a.btn.btn-small.btn-success{:href => method( :"#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child) } %i.icon-info-sign.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.show") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.show") - if can? :edit, child %a.btn.btn-small.btn-warning{:href => method( :"edit_#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child) } %i.icon-edit.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.edit") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.edit") - if can? :destroy, child %a.btn.btn-small.btn-danger{"data-confirm" => t("#{child.class.name.underscore.pluralize}.index.actions.confirm_destroy"), "data-method" => "delete", :href => method( :"#{parent.class.name.underscore}_#{child.class.name.underscore}_path" ).(parent, child), :rel => "nofollow"} %i.icon-remove.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.destroy") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.destroy") - elsif !(defined? child).nil? %td @@ -22,15 +25,18 @@ - if can? :show, child %a.btn.btn-small.btn-success{:href => method( :"#{child.class.name.underscore}_path" ).(child) } %i.icon-info-sign.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.show") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.show") - if can? :edit, child %a.btn.btn-small.btn-warning{:href => method( :"edit_#{child.class.name.underscore}_path" ).(child) } %i.icon-edit.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.edit") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.edit") - if can? :destroy, child %a.btn.btn-small.btn-danger{"data-confirm" => t("#{child.class.name.underscore.pluralize}.index.actions.confirm_destroy"), "data-method" => "delete", :href => method( :"#{child.class.name.underscore}_path" ).(child), :rel => "nofollow"} %i.icon-trash.icon-white - =t("#{child.class.name.underscore.pluralize}.index.actions.destroy") + %span.hidden-phone + =t("#{child.class.name.underscore.pluralize}.index.actions.destroy")
\ No newline at end of file diff --git a/app/views/softkeys/_form_core.html.haml b/app/views/softkeys/_form_core.html.haml index b833aad..2863d5c 100644 --- a/app/views/softkeys/_form_core.html.haml +++ b/app/views/softkeys/_form_core.html.haml @@ -7,6 +7,6 @@ .inputs = f.input :softkey_function_id, :as => :select, :collection => @softkey_functions.map {|x| [I18n.t("softkeys.functions.#{x}"), x.id] }, :label => t('softkeys.form.function.label'), :hint => conditional_hint('softkeys.form.function.hint'), :include_blank => false - if @available_call_forwards && @available_call_forwards.count > 0 - = f.association :call_forward, :collection => @available_call_forwards, :label => t('softkeys.form.call_forward.label'), :hint => conditional_hint('softkeys.form.call_forward.hint'), :include_blank => false + = f.association :softkeyable, :collection => @available_call_forwards, :label => t('softkeys.form.call_forward.label'), :hint => conditional_hint('softkeys.form.call_forward.hint'), :include_blank => false = f.input :number, :label => t('softkeys.form.number.label'), :hint => conditional_hint('softkeys.form.number.hint') = f.input :label, :label => t('softkeys.form.label.label'), :hint => conditional_hint('softkeys.form.label.hint') diff --git a/app/views/softkeys/_index_core.html.haml b/app/views/softkeys/_index_core.html.haml index 398ee51..4a06c72 100644 --- a/app/views/softkeys/_index_core.html.haml +++ b/app/views/softkeys/_index_core.html.haml @@ -1,15 +1,21 @@ -%table.table.table-striped - %thead - %tr - %th= t('softkeys.index.function') - %th= t('softkeys.index.number') - %th= t('softkeys.index.label') - - %tbody - - for softkey in softkeys.order(:position) +- cache(['softkeys_table', I18n.locale, current_user, softkeys]) do + %table.table.table-striped + %thead %tr - %td - =softkey.to_s - %td= softkey.number - %td= softkey.label - =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => softkey.sip_account, :child => softkey}
\ No newline at end of file + %th + %th= t('softkeys.index.function') + %th= t('softkeys.index.number') + %th= t('softkeys.index.label') + + %tbody{ :id => "softkeys", :'data-update-url' => sort_softkeys_url} + - for softkey in softkeys + - cache(['softkeys_table_tr', I18n.locale, current_user, softkey]) do + = content_tag_for :tr, softkey do + %td + - if softkeys.count > 1 + %span.handle + %i.icon-resize-vertical + %td= t("softkeys.functions.#{softkey.softkey_function}") + %td= softkey.number + %td= softkey.label + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => softkey.sip_account, :child => softkey}
\ No newline at end of file diff --git a/app/views/softkeys/show.html.haml b/app/views/softkeys/show.html.haml index d0db111..7c068ae 100644 --- a/app/views/softkeys/show.html.haml +++ b/app/views/softkeys/show.html.haml @@ -1,7 +1,7 @@ - content_for :title, t("softkeys.show.page_title") %p - %strong= t('softkeys.show.function') + ":" + %strong= t("softkeys.functions.#{@softkey.softkey_function}") + ":" =@softkey.to_s -= render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @softkey.sip_account, :child => @softkey }
\ No newline at end of file += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @softkey.sip_account, :child => @softkey } diff --git a/app/views/system_messages/_form.html.haml b/app/views/system_messages/_form.html.haml deleted file mode 100644 index 036ee00..0000000 --- a/app/views/system_messages/_form.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -= simple_form_for([@user, @system_message]) do |f| - = f.error_notification - - = render "form_core", :f => f - - .actions - = f.button :submit, conditional_t('system_messages.form.submit')
\ No newline at end of file diff --git a/app/views/system_messages/_form_core.html.haml b/app/views/system_messages/_form_core.html.haml deleted file mode 100644 index a85db28..0000000 --- a/app/views/system_messages/_form_core.html.haml +++ /dev/null @@ -1,2 +0,0 @@ -.inputs - = f.input :content, :label => t('system_messages.form.content.label'), :hint => conditional_hint('system_messages.form.content.hint') diff --git a/app/views/system_messages/_index_core.html.haml b/app/views/system_messages/_index_core.html.haml deleted file mode 100644 index 7c9dab5..0000000 --- a/app/views/system_messages/_index_core.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -%table.table.table-striped - %thead - %tr - %th= t('system_messages.index.created_at') - %th= t('system_messages.index.content') - - %tbody - - for system_message in system_messages - %tr - %td= system_message.created_at - %td= system_message.content - =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => system_message}
\ No newline at end of file diff --git a/app/views/system_messages/index.html.haml b/app/views/system_messages/index.html.haml deleted file mode 100644 index ffd3fc3..0000000 --- a/app/views/system_messages/index.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- content_for :title, t("system_messages.index.page_title") - -= render "index_core", :system_messages => @system_messages
\ No newline at end of file diff --git a/app/views/system_messages/new.html.haml b/app/views/system_messages/new.html.haml deleted file mode 100644 index 565f5c5..0000000 --- a/app/views/system_messages/new.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- content_for :title, t("system_messages.new.page_title") - -= render "form" diff --git a/app/views/system_messages/show.html.haml b/app/views/system_messages/show.html.haml deleted file mode 100644 index 70be6f2..0000000 --- a/app/views/system_messages/show.html.haml +++ /dev/null @@ -1,8 +0,0 @@ -- content_for :title, t("system_messages.show.page_title") - -%p - %strong= t('system_messages.show.created_at') + ":" - = @system_message.created_at -%p - %strong= t('system_messages.show.content') + ":" - = @system_message.content diff --git a/app/views/tenants/_admin_area.html.haml b/app/views/tenants/_admin_area.de.html.haml index 28a8273..2aed4e1 100644 --- a/app/views/tenants/_admin_area.html.haml +++ b/app/views/tenants/_admin_area.de.html.haml @@ -23,7 +23,7 @@ %p Das System kann = PhoneModel.count - verschiedene Telefonmodelle von den folgenden Herstellern verwalten: + verschiedene Telefonmodelle von den folgenden Herstellern automatisch provisionieren: - Manufacturer.all.each do |manufacturer| - if manufacturer != Manufacturer.last && manufacturer != Manufacturer.limit(Manufacturer.count - 1).last = succeed ', ' do @@ -37,4 +37,6 @@ = render :partial => 'call_routes', :locals => {:tenant => tenant} - = render :partial => 'gateways', :locals => {:tenant => tenant, :gateways => gateways}
\ No newline at end of file + = render :partial => 'gateways', :locals => {:tenant => tenant, :gateways => gateways} + + = render :partial => 'table_of_backup_jobs', :locals => {:tenant => tenant, :backup_jobs => backup_jobs} diff --git a/app/views/tenants/_admin_area.en.html.haml b/app/views/tenants/_admin_area.en.html.haml new file mode 100644 index 0000000..8e7bfea --- /dev/null +++ b/app/views/tenants/_admin_area.en.html.haml @@ -0,0 +1,42 @@ + +.row + .span12 + = render :partial => 'tenants/table_of_sip_accounts', :locals => {:tenant => tenant} + - if SipAccount.any? + = render :partial => 'tenants/table_of_phones', :locals => {:tenant => tenant} + + - if SipAccount.any? || Gateway.any? + = render :partial => 'tenants/table_of_conferences', :locals => {:tenant => tenant} + = render :partial => 'tenants/table_of_callthroughs', :locals => {:tenant => tenant} + = render :partial => 'tenants/table_of_hunt_groups', :locals => {:tenant => tenant} + = render :partial => 'tenants/table_of_automatic_call_distributors', :locals => {:tenant => tenant} + + = render :partial => 'tenants/users_table', :locals => {:tenant => tenant} + = render :partial => 'tenants/user_groups_table', :locals => {:tenant => tenant} + + = render :partial => 'tenants/table_of_phone_books', :locals => {:tenant => tenant} + + .well + %h2 Gemeinschaft Configuration + = render :partial => 'tenants/gs_parameter_table', :locals => {:tenant => tenant} + + %p + This system can provision a total of + = PhoneModel.count + different phone models of the following manufacturers: + - Manufacturer.all.each do |manufacturer| + - if manufacturer != Manufacturer.last && manufacturer != Manufacturer.limit(Manufacturer.count - 1).last + = succeed ', ' do + =link_to link_to Haml::Engine.new("%i.icon-list").render + ' ' + manufacturer, manufacturer_path(manufacturer) + - elsif manufacturer == Manufacturer.limit(Manufacturer.count - 1).last + = succeed ' and ' do + =link_to link_to Haml::Engine.new("%i.icon-list").render + ' ' + manufacturer, manufacturer_path(manufacturer) + - else + = succeed '.' do + =link_to link_to Haml::Engine.new("%i.icon-list").render + ' ' + manufacturer, manufacturer_path(manufacturer) + + = render :partial => 'call_routes', :locals => {:tenant => tenant} + + = render :partial => 'gateways', :locals => {:tenant => tenant, :gateways => gateways} + + = render :partial => 'table_of_backup_jobs', :locals => {:tenant => tenant, :backup_jobs => backup_jobs}
\ No newline at end of file diff --git a/app/views/tenants/_table_of_backup_jobs.html.haml b/app/views/tenants/_table_of_backup_jobs.html.haml new file mode 100644 index 0000000..a585010 --- /dev/null +++ b/app/views/tenants/_table_of_backup_jobs.html.haml @@ -0,0 +1,11 @@ +-# BackupJobs +-# +- if (can?( :index, BackupJob ) && backup_jobs.count > 0 ) || can?( :create, BackupJob ) + - if backup_jobs.count == BackupJob.count + %h2= t('backup_jobs.index.page_title') + - else + %h2= t('backup_jobs.index.page_title_with_limit', :limit => '5') + + - if can?( :index, BackupJob ) && backup_jobs.count > 0 + = render "backup_jobs/index_core", :backup_jobs => backup_jobs + = render :partial => 'shared/create_link', :locals => {:child_class => BackupJob}
\ No newline at end of file diff --git a/app/views/tenants/show.html.haml b/app/views/tenants/show.html.haml index 818e584..23ec81a 100644 --- a/app/views/tenants/show.html.haml +++ b/app/views/tenants/show.html.haml @@ -15,4 +15,4 @@ = render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @tenant } - if @tenant.user_groups.where(:name => 'Admins').any? && @tenant.user_groups.where(:name => 'Admins').first.users.include?(current_user) - = render :partial => 'admin_area', :locals => { :tenant => @tenant, :gateways => @gateways}
\ No newline at end of file + = render :partial => 'admin_area', :locals => { :tenant => @tenant, :gateways => @gateways, :backup_jobs => @backup_jobs}
\ No newline at end of file diff --git a/config/backup.rb b/config/backup.rb new file mode 100644 index 0000000..e5816c1 --- /dev/null +++ b/config/backup.rb @@ -0,0 +1,60 @@ +# encoding: utf-8 + +require 'inifile' +SYSTEM_ODBC_CONFIGURATION = IniFile.load('/var/lib/freeswitch/.odbc.ini') + +Backup::Model.new(:GS5, 'GS5 backup') do + + ## + # Split [Splitter] + # + # Split the backup file in to chunks of 2 GB + # if the backup file size exceeds 2 GB + # + # split_into_chunks_of 2048 + + ## + # MySQL [Database] + # + database MySQL do |db| + # To dump all databases, set `db.name = :all` (or leave blank) + db.name = SYSTEM_ODBC_CONFIGURATION['gemeinschaft']['DATABASE'] + db.username = SYSTEM_ODBC_CONFIGURATION['gemeinschaft']['USER'] + db.password = SYSTEM_ODBC_CONFIGURATION['gemeinschaft']['PASSWORD'] + db.host = "localhost" + db.port = 3306 + db.socket = "/var/run/mysqld/mysqld.sock" + end + + ## + # Faxes + # + if File.exists?('/opt/gemeinschaft/public/uploads/fax_document') + archive :faxes do |archive| + archive.add '/opt/gemeinschaft/public/uploads/fax_document' + end + end + + ## + # Voicemails + # + if File.exists?('/var/opt/gemeinschaft/freeswitch/voicemail') + archive :voicemails do |archive| + archive.add '/var/opt/gemeinschaft/freeswitch/voicemail' + end + end + + ## + # Local (Copy) [Storage] + # + store_with Local do |local| + local.path = "/var/backups/" + end + + ## + # Gzip [Compressor] + # + compress_with Gzip + +end + diff --git a/config/locales/de.yml b/config/locales/de.yml index 9d85d8e..ffc8e69 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -192,7 +192,7 @@ de: formats: default: ! '%A, %d. %B %Y, %H:%M Uhr' long: ! '%A, %d. %B %Y, %H:%M Uhr' - short: ! '%d. %B, %H:%M Uhr' + short: ! '%d.%m.%Y %H:%M Uhr' pm: nachmittags date_only: '%d.%m.%Y' misc: diff --git a/config/locales/navigation.de.yml b/config/locales/navigation.de.yml new file mode 100644 index 0000000..779248c --- /dev/null +++ b/config/locales/navigation.de.yml @@ -0,0 +1,3 @@ +de: + navigation: + admin_docu: 'Admin-Doku'
\ No newline at end of file diff --git a/config/locales/navigation.en.yml b/config/locales/navigation.en.yml new file mode 100644 index 0000000..82e901b --- /dev/null +++ b/config/locales/navigation.en.yml @@ -0,0 +1,3 @@ +en: + navigation: + admin_docu: 'Admin-Docu'
\ No newline at end of file diff --git a/config/locales/views/backup_jobs/de.yml b/config/locales/views/backup_jobs/de.yml new file mode 100644 index 0000000..8e23feb --- /dev/null +++ b/config/locales/views/backup_jobs/de.yml @@ -0,0 +1,61 @@ +de: + backup_jobs: + name: 'Backup-Auftrag' + controller: + successfuly_created: 'Backup-Auftrag wurde angelegt.' + successfuly_updated: 'Backup-Auftrag wurde aktualisiert.' + successfuly_destroyed: 'Backup-Auftrag wurde gelöscht.' + index: + page_title: 'Liste aller Backup-Aufträge' + page_title_with_limit: 'Liste der letzten %{limit} Backup-Aufträge' + started_at: 'Start' + finished_at: 'Ende' + state: 'Status' + directory: 'Verzeichnis' + size_of_the_backup: 'Größe' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Backup-Auftrag' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Backup-Auftrag neu anlegen für %{resource}' + show: + page_title: 'Backup-Auftrag bearbeiten' + started_at: 'Start' + finished_at: 'Ende' + state: 'Status' + directory: 'Verzeichnis' + size_of_the_backup: 'Größe' + actions: + confirm_destroy: 'Sind Sie sicher, dass die dieses Element löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Backup-Auftrag neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Backup-Auftrag bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + started_at: + label: 'Start' + hint: '' + finished_at: + label: 'Ende' + hint: '' + state: + label: 'Status' + hint: '' + directory: + label: 'Verzeichnis' + hint: '' + size_of_the_backup: + label: 'Größe' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/backup_jobs/en.yml b/config/locales/views/backup_jobs/en.yml new file mode 100644 index 0000000..74d14c2 --- /dev/null +++ b/config/locales/views/backup_jobs/en.yml @@ -0,0 +1,61 @@ +en: + backup_jobs: + name: 'Backup job' + controller: + successfuly_created: 'Successfully created backup job.' + successfuly_updated: 'Successfully updated backup job.' + successfuly_destroyed: 'Successfully destroyed backup job.' + index: + page_title: 'Listing backup jobs' + page_title_with_limit: 'Listing of the last %{limit} backup jobs' + started_at: 'Started at' + finished_at: 'Finished at' + state: 'State' + directory: 'Directory' + size_of_the_backup: 'Size of the backup' + actions: + confirm_destroy: 'Are you sure you want to delete this backup job?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New backup job for %{resource}' + show: + page_title: 'Show backup job' + started_at: 'Started at' + finished_at: 'Finished at' + state: 'State' + directory: 'Directory' + size_of_the_backup: 'Size of the backup' + actions: + confirm_destroy: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New backup job' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing backup job' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + started_at: + label: 'Started at' + hint: '' + finished_at: + label: 'Finished at' + hint: '' + state: + label: 'State' + hint: '' + directory: + label: 'Directory' + hint: '' + size_of_the_backup: + label: 'Size of the backup' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/call_routes/de.yml b/config/locales/views/call_routes/de.yml index a8d6f4b..c9df1c2 100644 --- a/config/locales/views/call_routes/de.yml +++ b/config/locales/views/call_routes/de.yml @@ -1,25 +1,25 @@ de: call_routes: - name: 'Call Route' + name: 'Call-Route' controller: - successfuly_created: 'Call Route wurde angelegt.' - successfuly_updated: 'Call Route wurde aktualisiert.' - successfuly_destroyed: 'Call Route wurde gelöscht.' + successfuly_created: 'Call-Route wurde angelegt.' + successfuly_updated: 'Call-Route wurde aktualisiert.' + successfuly_destroyed: 'Call-Route wurde gelöscht.' index: - page_title: 'Liste aller Call Routen' - routing_table: 'Routing Table' + page_title: 'Liste Call-Routen' + routing_table: 'Routing Tabelle' name: 'Name' - endpoint: 'Endpoint' + endpoint: 'Endpunkt' position: 'Position' actions: - confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Call Route' + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Call-Route' destroy: 'Löschen' edit: 'Bearbeiten' show: 'Anzeigen' create: 'Neu anlegen' - create_for: 'Call Route neu anlegen für %{resource}' + create_for: 'Call-Route neu anlegen für %{resource}' show: - page_title: 'Call Route bearbeiten' + page_title: 'Call-Route bearbeiten' routing_table: 'Routing Table' name: 'Name' endpoint: 'Endpoint' @@ -30,11 +30,11 @@ de: edit: 'Bearbeiten' view_all: 'Alle anzeigen' new: - page_title: 'Call Route neu anlegen' + page_title: 'Call-Route neu anlegen' actions: back_to_list: 'Zurück zur Übersicht' edit: - page_title: 'Call Route bearbeiten' + page_title: 'Call-Route bearbeiten' actions: back_to_list: 'Zurück zur Übersicht' edit: 'Bearbeiten' @@ -46,10 +46,7 @@ de: name: label: 'Name' hint: '' - endpoint_type: - label: 'Endpoint type' - hint: '' - endpoint_id: + endpoint: label: 'Endpoint' hint: '' position: diff --git a/config/locales/views/call_routes/en.yml b/config/locales/views/call_routes/en.yml index 8596474..c37773d 100644 --- a/config/locales/views/call_routes/en.yml +++ b/config/locales/views/call_routes/en.yml @@ -46,10 +46,7 @@ en: name: label: 'Name' hint: '' - endpoint_type: - label: 'Endpoint type' - hint: '' - endpoint_id: + endpoint: label: 'Endpoint' hint: '' position: diff --git a/config/locales/views/gemeinschaft_setups/de.yml b/config/locales/views/gemeinschaft_setups/de.yml index 57bc7e6..eb0145c 100644 --- a/config/locales/views/gemeinschaft_setups/de.yml +++ b/config/locales/views/gemeinschaft_setups/de.yml @@ -28,6 +28,9 @@ de: default_area_code: label: 'Standard Ortsvorwahl' hint: '030 für Berlin, 0261 für Koblenz, 02631 für Neuwied, usw.' + trunk_access_code: + label: 'Amtsholungsziffer' + hint: '' default_company_name: label: 'Name der Organisation' hint: 'z.B. Firmenname' diff --git a/config/locales/views/gemeinschaft_setups/en.yml b/config/locales/views/gemeinschaft_setups/en.yml index 9d5f965..3a1ac39 100644 --- a/config/locales/views/gemeinschaft_setups/en.yml +++ b/config/locales/views/gemeinschaft_setups/en.yml @@ -28,6 +28,9 @@ en: default_area_code: label: 'Default area code' hint: '' + trunk_access_code: + label: 'Trunk access code' + hint: '' default_company_name: label: 'Name of the organisation' hint: 'e.g. name of the company' diff --git a/config/locales/views/intruders/de.yml b/config/locales/views/intruders/de.yml new file mode 100644 index 0000000..42ece4b --- /dev/null +++ b/config/locales/views/intruders/de.yml @@ -0,0 +1,110 @@ +de: + intruders: + name: 'Intruder' + controller: + successfuly_created: 'Intruder wurde angelegt.' + successfuly_updated: 'Intruder wurde aktualisiert.' + successfuly_destroyed: 'Intruder wurde gelöscht.' + index: + page_title: 'Übersicht von Intruder' + list_type: 'List type' + key: 'Key' + points: 'Points' + bans: 'Bans' + ban_last: 'Ban last' + ban_end: 'Ban end' + contact_ip: 'Contact ip' + contact_port: 'Contact port' + contact_count: 'Contact count' + contact_last: 'Contact last' + contacts_per_second: 'Contacts per second' + contacts_per_second_max: 'Contacts per second max' + user_agent: 'User agent' + to_user: 'To user' + comment: 'Comment' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Intruder' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Intruder neu anlegen für %{resource}' + show: + page_title: 'Intruder bearbeiten' + list_type: 'List type' + key: 'Key' + points: 'Points' + bans: 'Bans' + ban_last: 'Ban last' + ban_end: 'Ban end' + contact_ip: 'Contact ip' + contact_port: 'Contact port' + contact_count: 'Contact count' + contact_last: 'Contact last' + contacts_per_second: 'Contacts per second' + contacts_per_second_max: 'Contacts per second max' + user_agent: 'User agent' + to_user: 'To user' + comment: 'Comment' + actions: + confirm_destroy: 'Sind Sie sicher, dass die dieses Element löschen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + new: + page_title: 'Intruder neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Intruder bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + list_type: + label: 'List type' + hint: '' + key: + label: 'Key' + hint: '' + points: + label: 'Points' + hint: '' + bans: + label: 'Bans' + hint: '' + ban_last: + label: 'Ban last' + hint: '' + ban_end: + label: 'Ban end' + hint: '' + contact_ip: + label: 'Contact ip' + hint: '' + contact_port: + label: 'Contact port' + hint: '' + contact_count: + label: 'Contact count' + hint: '' + contact_last: + label: 'Contact last' + hint: '' + contacts_per_second: + label: 'Contacts per second' + hint: '' + contacts_per_second_max: + label: 'Contacts per second max' + hint: '' + user_agent: + label: 'User agent' + hint: '' + to_user: + label: 'To user' + hint: '' + comment: + label: 'Comment' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/intruders/en.yml b/config/locales/views/intruders/en.yml new file mode 100644 index 0000000..99c2dcb --- /dev/null +++ b/config/locales/views/intruders/en.yml @@ -0,0 +1,110 @@ +en: + intruders: + name: 'Intruder' + controller: + successfuly_created: 'Successfully created Intruder.' + successfuly_updated: 'Successfully updated Intruder.' + successfuly_destroyed: 'Successfully destroyed Intruder.' + index: + page_title: 'Listing Intruder' + list_type: 'List type' + key: 'Key' + points: 'Points' + bans: 'Bans' + ban_last: 'Ban last' + ban_end: 'Ban end' + contact_ip: 'Contact ip' + contact_port: 'Contact port' + contact_count: 'Contact count' + contact_last: 'Contact last' + contacts_per_second: 'Contacts per second' + contacts_per_second_max: 'Contacts per second max' + user_agent: 'User agent' + to_user: 'To user' + comment: 'Comment' + actions: + confirm_destroy: 'Are you sure you want to delete this Intruder?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Intruder for %{resource}' + show: + page_title: 'Show Intruder' + list_type: 'List type' + key: 'Key' + points: 'Points' + bans: 'Bans' + ban_last: 'Ban last' + ban_end: 'Ban end' + contact_ip: 'Contact ip' + contact_port: 'Contact port' + contact_count: 'Contact count' + contact_last: 'Contact last' + contacts_per_second: 'Contacts per second' + contacts_per_second_max: 'Contacts per second max' + user_agent: 'User agent' + to_user: 'To user' + comment: 'Comment' + actions: + confirm_destroy: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New Intruder' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Intruder' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + list_type: + label: 'List type' + hint: '' + key: + label: 'Key' + hint: '' + points: + label: 'Points' + hint: '' + bans: + label: 'Bans' + hint: '' + ban_last: + label: 'Ban last' + hint: '' + ban_end: + label: 'Ban end' + hint: '' + contact_ip: + label: 'Contact ip' + hint: '' + contact_port: + label: 'Contact port' + hint: '' + contact_count: + label: 'Contact count' + hint: '' + contact_last: + label: 'Contact last' + hint: '' + contacts_per_second: + label: 'Contacts per second' + hint: '' + contacts_per_second_max: + label: 'Contacts per second max' + hint: '' + user_agent: + label: 'User agent' + hint: '' + to_user: + label: 'To user' + hint: '' + comment: + label: 'Comment' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/phones/de.yml b/config/locales/views/phones/de.yml index 373db13..02875c4 100644 --- a/config/locales/views/phones/de.yml +++ b/config/locales/views/phones/de.yml @@ -9,9 +9,9 @@ de: page_title: 'Telefone' mac_address: 'MAC-Adresse' phone_model_id: 'Modell' - hot_deskable: 'Hot-Desk fähig' - ip_address: 'IP-Adresse' - last_ip_address: 'Letzte IP-Adresse' + hot_deskable: 'Hot-Desk' + ip_address: 'IP' + last_ip_address: 'Letzte IP' http_user: 'Phone WebGUI Username' http_password: 'Phone WebGUI Passwort' nightly_reboot: 'Nachts automatischer Reboot' diff --git a/config/locales/views/route_elements/de.yml b/config/locales/views/route_elements/de.yml index fe14671..70a6162 100644 --- a/config/locales/views/route_elements/de.yml +++ b/config/locales/views/route_elements/de.yml @@ -1,12 +1,12 @@ de: route_elements: - name: 'Route element' + name: 'Routen-Element' controller: - successfuly_created: 'Route element wurde angelegt.' - successfuly_updated: 'Route element wurde aktualisiert.' - successfuly_destroyed: 'Route element wurde gelöscht.' + successfuly_created: 'Routen-Element wurde angelegt.' + successfuly_updated: 'Routen-Element wurde aktualisiert.' + successfuly_destroyed: 'Routen-Element wurde gelöscht.' index: - page_title: 'Übersicht von Route element' + page_title: 'Liste Routen-Elemente' call_route_id: 'Call route' var_in: 'Var in' var_out: 'Var out' @@ -16,14 +16,14 @@ de: mandatory: 'Mandatory' position: 'Position' actions: - confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Route element' + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Routen-Element' destroy: 'Löschen' edit: 'Bearbeiten' show: 'Anzeigen' create: 'Neu anlegen' - create_for: 'Route element neu anlegen für %{resource}' + create_for: 'Routen-Element neu anlegen für %{resource}' show: - page_title: 'Route element bearbeiten' + page_title: 'Routen-Element bearbeiten' call_route_id: 'Call route' var_in: 'Var in' var_out: 'Var out' @@ -38,11 +38,11 @@ de: edit: 'Bearbeiten' view_all: 'Alle anzeigen' new: - page_title: 'Route element neu anlegen' + page_title: 'Routen-Element neu anlegen' actions: back_to_list: 'Zurück zur Übersicht' edit: - page_title: 'Route element bearbeiten' + page_title: 'Routen-Element bearbeiten' actions: back_to_list: 'Zurück zur Übersicht' edit: 'Bearbeiten' diff --git a/config/locales/views/sip_accounts/de.yml b/config/locales/views/sip_accounts/de.yml index 2820336..8fe2300 100644 --- a/config/locales/views/sip_accounts/de.yml +++ b/config/locales/views/sip_accounts/de.yml @@ -11,11 +11,11 @@ de: caller_name: 'Caller Name' password: 'Passwort' voicemail_pin: 'Anrufbeantworter PIN' - phone_numbers: 'Telefonnummern' + phone_numbers: 'Tel.Nr.' call_waiting: 'Anklopfen' clir: 'Rufnummernunterdrückung (CLIR)' clip: 'Rufnummernanzeige (CLIP)' - hotdeskable: 'Hot-Desk fähig' + hotdeskable: 'Hot-Desk' clip_no_screening: 'Spezifische Rufnummernanzeige (CLIP -no screening-)' callforward_rules_act_per_sip_account: 'Rufweiterleitungen gelten für das gesamte SIP-Account' online: 'Online' diff --git a/config/locales/views/system_messages/de.yml b/config/locales/views/system_messages/de.yml deleted file mode 100644 index d841d0b..0000000 --- a/config/locales/views/system_messages/de.yml +++ /dev/null @@ -1,38 +0,0 @@ -de: - system_messages: - name: 'Systemnachricht' - controller: - successfuly_created: 'Eine Systemnachricht wurde erstellt.' - successfuly_updated: 'Eine Systemnachricht wurde aktualisiert.' - successfuly_destroyed: 'Eine Systemnachricht wurde gelöscht.' - index: - page_title: 'Systemnachrichten' - user_id: 'Benutzer' - content: 'Nachricht' - actions: - confirm_destroy: 'Sind Sie sicher, dass Sie diese Systemnachricht löschen möchten?' - destroy: 'Löschen' - edit: 'Bearbeiten' - show: 'Anzeigen' - create: 'Neu anlegen' - show: - page_title: 'Systemnachricht anzeigen' - user_id: 'Benutzer' - content: 'Nachricht' - actions: - confirm_destroy: 'Sind Sie sicher, dass Sie diese Systemnachricht löschen möchten?' - destroy: 'Löschen' - edit: 'Bearbeiten' - view_all: 'Alle anzeigen' - new: - page_title: 'Neue Systemnachricht' - edit: - page_title: 'Systemnachricht bezüglich %{resource} bearbeiten' - form: - user_id: - label: 'Benutzer' - hint: '' - content: - label: 'Nachricht' - hint: '' - submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/system_messages/en.yml b/config/locales/views/system_messages/en.yml deleted file mode 100644 index a039b10..0000000 --- a/config/locales/views/system_messages/en.yml +++ /dev/null @@ -1,38 +0,0 @@ -en: - system_messages: - name: 'System message' - controller: - successfuly_created: 'Successfully created System message.' - successfuly_updated: 'Successfully updated System message.' - successfuly_destroyed: 'Successfully destroyed System message.' - index: - page_title: 'System messages' - user_id: 'User' - content: 'Content' - actions: - confirm_destroy: 'Are you sure you want to delete this element?' - destroy: 'Delete' - edit: 'Edit' - show: 'View' - create: 'New' - show: - page_title: 'Editing System message' - user_id: 'User' - content: 'Content' - actions: - confirm_destroy: 'Are you sure you want to delete this element?' - destroy: 'Delete' - edit: 'Edit' - view_all: 'View All' - new: - page_title: 'New System message' - edit: - page_title: 'Editing System message %{resource}' - form: - user_id: - label: 'User' - hint: '' - content: - label: 'Content' - hint: '' - submit: 'Submit'
\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 9d47efc..6d7a2ad 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,20 +1,21 @@ Gemeinschaft42c::Application.routes.draw do + resources :intruders + + resources :backup_jobs, :except => [:edit, :update] + scope :constraints => lambda{|req|%w(127.0.0.1).include? req.remote_addr} do get "trigger/voicemail" get "trigger/fax" end resources :call_routes do + collection { + post :sort + get :show_variables + } resources :route_elements do - member do - put 'move_higher' - put 'move_lower' - end - end - member do - put 'move_higher' - put 'move_lower' + collection { post :sort } end end @@ -41,95 +42,54 @@ Gemeinschaft42c::Application.routes.draw do resources :rows end + resources :phone_numbers, :only => [:sort] do + collection { post :sort } + end + resources :acd_agents, :only => [] do - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :automatic_call_distributors, :only => [] do resources :acd_agents - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :hunt_group_members, :only => [] do - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :hunt_groups, :only => [] do resources :hunt_group_members - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end if GsParameter.get('CALLTHROUGH_HAS_WHITELISTS') == true resources :whitelists, :only => [] do - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end end resources :access_authorizations, :only => [] do - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :fax_documents resources :fax_accounts, :only => [] do resources :fax_documents - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :gemeinschaft_setups, :only => [:new, :create] - + resources :phone_number_ranges, :only => [] do - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :conferences, :only => [] do resources :conference_invitees - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers end resources :phone_numbers, :only => [] do @@ -228,9 +188,6 @@ Gemeinschaft42c::Application.routes.draw do root :to => "page#index" - get "wizards/new_initial_setup" - post "wizards/create_initial_setup" - resources :users do # Display all phone books that the current user owns: resources :phone_books @@ -271,31 +228,20 @@ Gemeinschaft42c::Application.routes.draw do resources :callthroughs, :only => [] do resources :access_authorizations - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers if GsParameter.get('CALLTHROUGH_HAS_WHITELISTS') == true resources :whitelists end end + resources :softkeys, :only => [ :sort ] do + collection { post :sort } + end + resources :sip_accounts, :only => [] do resources :phones_sip_accounts - resources :phone_numbers do - member do - put 'move_higher' - put 'move_lower' - end - end - resources :softkeys do - member do - put 'move_higher' - put 'move_lower' - end - end + resources :phone_numbers + resources :softkeys resources :call_histories do collection do delete 'destroy_multiple' @@ -325,8 +271,6 @@ Gemeinschaft42c::Application.routes.draw do resources :phone_book_entries, :only => [ :index, :show ] do resources :phone_numbers do member do - put 'move_higher' - put 'move_lower' put 'call' end end diff --git a/config/schedule.rb b/config/schedule.rb new file mode 100644 index 0000000..0b5f0ca --- /dev/null +++ b/config/schedule.rb @@ -0,0 +1,24 @@ +# Use this file to easily define all of your cron jobs. +# +# It's helpful, but not entirely necessary to understand cron before proceeding. +# http://en.wikipedia.org/wiki/Cron + +# Example: +# +# set :output, "/path/to/my/cron_log.log" +# +# every 2.hours do +# command "/usr/bin/some_great_command" +# runner "MyModel.some_method" +# rake "some:great:rake:task" +# end +# +# every 4.days do +# runner "AnotherModel.prune_old_records" +# end + +every 1.day, :at => '4:00 am' do + rake "backup:daily_backup" +end + +# Learn more: http://github.com/javan/whenever diff --git a/db/migrate/20120127101726_create_system_messages.rb b/db/migrate/20120127101726_create_system_messages.rb deleted file mode 100644 index 830f54a..0000000 --- a/db/migrate/20120127101726_create_system_messages.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CreateSystemMessages < ActiveRecord::Migration - def self.up - create_table :system_messages do |t| - t.integer :user_id - t.string :content - t.timestamps - end - end - - def self.down - drop_table :system_messages - end -end diff --git a/db/migrate/20130129154700_add_sso_key.rb b/db/migrate/20130129154700_add_sso_key.rb new file mode 100644 index 0000000..2e47f39 --- /dev/null +++ b/db/migrate/20130129154700_add_sso_key.rb @@ -0,0 +1,9 @@ +class AddSsoKey < ActiveRecord::Migration + def up + GsParameter.create(:name => 'SingleSignOnEnvUserNameKey', :section => 'Generic', :value => '', :class_type => 'Nil', :description => 'When set to a string this env variable will be used to authenticate the user. e.g. REMOTE_USER') + end + + def down + GsParameter.create(:name => 'SingleSignOnEnvUserNameKey').destroy_all + end +end diff --git a/db/migrate/20130130185300_add_no_copy_headers.rb b/db/migrate/20130130185300_add_no_copy_headers.rb new file mode 100644 index 0000000..aa96653 --- /dev/null +++ b/db/migrate/20130130185300_add_no_copy_headers.rb @@ -0,0 +1,9 @@ +class AddNoCopyHeaders < ActiveRecord::Migration + def up + GsParameter.create(:entity => 'dialplan', :section => 'variables', :name => 'sip_copy_custom_headers', :value => 'false', :class_type => 'Boolean', :description => 'Controls passing SIP headers from one call leg to another.') + end + + def down + GsParameter.where(:entity => 'dialplan', :section => 'variables', :name => 'sip_copy_custom_headers').destroy_all + end +end diff --git a/db/migrate/20130202140927_add_trunk_access_code_to_gemeinschaft_setup.rb b/db/migrate/20130202140927_add_trunk_access_code_to_gemeinschaft_setup.rb new file mode 100644 index 0000000..82fa3ad --- /dev/null +++ b/db/migrate/20130202140927_add_trunk_access_code_to_gemeinschaft_setup.rb @@ -0,0 +1,5 @@ +class AddTrunkAccessCodeToGemeinschaftSetup < ActiveRecord::Migration + def change + add_column :gemeinschaft_setups, :trunk_access_code, :string + end +end diff --git a/db/migrate/20130203164500_remove_perimeter_parameters.rb b/db/migrate/20130203164500_remove_perimeter_parameters.rb new file mode 100644 index 0000000..8c37174 --- /dev/null +++ b/db/migrate/20130203164500_remove_perimeter_parameters.rb @@ -0,0 +1,16 @@ +class RemovePerimeterParameters < ActiveRecord::Migration + def up + GsParameter.where(:entity => 'perimeter', :section => 'general', :name => 'malicious_contact_count').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'general', :name => 'malicious_contact_time_span').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'general', :name => 'ban_futile').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'general', :name => 'execute').destroy_all + + end + + def down + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'malicious_contact_count', :value => 20, :class_type => 'Integer') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'malicious_contact_time_span', :value => 2, :class_type => 'Integer') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_futile', :value => 5, :class_type => 'Integer') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'execute', :value => 'sudo /usr/local/bin/ban_ip.sh {ip_address}', :class_type => 'String') + end +end diff --git a/db/migrate/20130203165800_add_perimeter_parameters.rb b/db/migrate/20130203165800_add_perimeter_parameters.rb new file mode 100644 index 0000000..23e0157 --- /dev/null +++ b/db/migrate/20130203165800_add_perimeter_parameters.rb @@ -0,0 +1,23 @@ +class AddPerimeterParameters < ActiveRecord::Migration + def up + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'contact_count_threshold', :value => '10', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'contact_span_threshold', :value => '2', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'name_changes_threshold', :value => '5', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_threshold', :value => '20', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_tries', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'blacklist_file', :value => '/var/opt/gemeinschaft/firewall/blacklist', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'blacklist_file_comment', :value => '# PERIMETER_BAN - points: {points}, generated: {date}', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'blacklist_file_entry', :value => '{received_ip} udp 5060', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_command', :value => 'sudo /sbin/service shorewall refresh', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_username_scan', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'to_user', :value => '^%d+', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'auth_result', :value => '^FORBIDDEN$', :class_type => 'String', :description => '') + end + + def down + GsParameter.where(:entity => 'perimeter').destroy_all + end +end diff --git a/db/migrate/20130203174300_start_perimeter_defense.rb b/db/migrate/20130203174300_start_perimeter_defense.rb new file mode 100644 index 0000000..15838bb --- /dev/null +++ b/db/migrate/20130203174300_start_perimeter_defense.rb @@ -0,0 +1,10 @@ +class StartPerimeterDefense < ActiveRecord::Migration + def up + module_index = GsParameter.where(:entity => 'events', :section => 'modules').all.count + 1; + GsParameter.create(:entity => 'events', :section => 'modules', :name => 'perimeter_defense', :value => module_index, :class_type => 'Integer') + end + + def down + GsParameter.where(:entity => 'events', :section => 'modules', :name => 'perimeter_defense').destroy_all + end +end diff --git a/db/migrate/20130204065900_split_perimeter_parameters.rb b/db/migrate/20130204065900_split_perimeter_parameters.rb new file mode 100644 index 0000000..b29bb29 --- /dev/null +++ b/db/migrate/20130204065900_split_perimeter_parameters.rb @@ -0,0 +1,30 @@ +class SplitPerimeterParameters < ActiveRecord::Migration + def up + GsParameter.where(:entity => 'perimeter', :section => 'checks').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers').destroy_all + GsParameter.create(:entity => 'perimeter', :section => 'general', :name => 'ban_command', :value => 'sudo /sbin/service shorewall refresh', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_username_scan', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_register', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_call', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks_call', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'to_user', :value => '^%d+', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_register', :name => 'auth_result', :value => '^FORBIDDEN$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_call', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers_call', :name => 'hangup_cause', :value => '^MANDATORY_IE_MISSING', :class_type => 'String', :description => '') + end + + def down + GsParameter.where(:entity => 'perimeter', :section => 'checks_register').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'checks_call').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers_register').destroy_all + GsParameter.where(:entity => 'perimeter', :section => 'bad_headers_call').destroy_all + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_frequency', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_username_scan', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'checks', :name => 'check_bad_headers', :value => '1', :class_type => 'Integer', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'user_agent', :value => '^friendly.scanner$', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'to_user', :value => '^%d+', :class_type => 'String', :description => '') + GsParameter.create(:entity => 'perimeter', :section => 'bad_headers', :name => 'auth_result', :value => '^FORBIDDEN$', :class_type => 'String', :description => '') + end +end diff --git a/db/migrate/20130205102838_create_backup_jobs.rb b/db/migrate/20130205102838_create_backup_jobs.rb new file mode 100644 index 0000000..0994939 --- /dev/null +++ b/db/migrate/20130205102838_create_backup_jobs.rb @@ -0,0 +1,16 @@ +class CreateBackupJobs < ActiveRecord::Migration + def self.up + create_table :backup_jobs do |t| + t.datetime :started_at + t.datetime :finished_at + t.string :state + t.string :directory + t.integer :size_of_the_backup + t.timestamps + end + end + + def self.down + drop_table :backup_jobs + end +end diff --git a/db/migrate/20130205151844_add_queue_to_delayed_jobs.rb b/db/migrate/20130205151844_add_queue_to_delayed_jobs.rb new file mode 100644 index 0000000..072c8d4 --- /dev/null +++ b/db/migrate/20130205151844_add_queue_to_delayed_jobs.rb @@ -0,0 +1,9 @@ +class AddQueueToDelayedJobs < ActiveRecord::Migration + def self.up + add_column :delayed_jobs, :queue, :string + end + + def self.down + remove_column :delayed_jobs, :queue + end +end diff --git a/db/migrate/20130206144829_add_backup_file_to_backup_job.rb b/db/migrate/20130206144829_add_backup_file_to_backup_job.rb new file mode 100644 index 0000000..e02f2b3 --- /dev/null +++ b/db/migrate/20130206144829_add_backup_file_to_backup_job.rb @@ -0,0 +1,5 @@ +class AddBackupFileToBackupJob < ActiveRecord::Migration + def change + add_column :backup_jobs, :backup_file, :string + end +end diff --git a/db/migrate/20130207082728_remove_size_of_the_backup_from_backup_job.rb b/db/migrate/20130207082728_remove_size_of_the_backup_from_backup_job.rb new file mode 100644 index 0000000..a902fd2 --- /dev/null +++ b/db/migrate/20130207082728_remove_size_of_the_backup_from_backup_job.rb @@ -0,0 +1,9 @@ +class RemoveSizeOfTheBackupFromBackupJob < ActiveRecord::Migration + def up + remove_column :backup_jobs, :size_of_the_backup + end + + def down + add_column :backup_jobs, :size_of_the_backup, :string + end +end diff --git a/db/migrate/20130208065700_add_softkeyable_to_softkey.rb b/db/migrate/20130208065700_add_softkeyable_to_softkey.rb new file mode 100644 index 0000000..deae9a0 --- /dev/null +++ b/db/migrate/20130208065700_add_softkeyable_to_softkey.rb @@ -0,0 +1,16 @@ +class AddSoftkeyableToSoftkey < ActiveRecord::Migration + def up + add_column :softkeys, :softkeyable_type, :string + add_column :softkeys, :softkeyable_id, :integer + Softkey.where('call_forward_id > 0').each do |softkey| + softkey.update_attributes( :softkeyable_type => 'CallForward', :softkeyable_id => softkey.call_forward_id ) + end + remove_column :softkeys, :call_forward_id + end + + def down + remove_column :softkeys, :softkeyable_type + remove_column :softkeys, :softkeyable_id + add_column :softkeys, :call_forward_id, :integer + end +end diff --git a/db/migrate/20130210075617_create_intruders.rb b/db/migrate/20130210075617_create_intruders.rb new file mode 100644 index 0000000..fc944cc --- /dev/null +++ b/db/migrate/20130210075617_create_intruders.rb @@ -0,0 +1,28 @@ +class CreateIntruders < ActiveRecord::Migration + def self.up + create_table :intruders do |t| + t.string :list_type + t.string :key + t.integer :points + t.integer :bans + t.datetime :ban_last + t.datetime :ban_end + t.string :contact_ip + t.integer :contact_port + t.integer :contact_count + t.datetime :contact_last + t.float :contacts_per_second + t.float :contacts_per_second_max + t.string :user_agent + t.string :to_user + t.string :comment + t.timestamps + end + + add_index :intruders, :key, :unique => true + end + + def self.down + drop_table :intruders + end +end diff --git a/db/migrate/20130212071000_default_profile_to_template.rb b/db/migrate/20130212071000_default_profile_to_template.rb new file mode 100644 index 0000000..d3fd89c --- /dev/null +++ b/db/migrate/20130212071000_default_profile_to_template.rb @@ -0,0 +1,13 @@ +class DefaultProfileToTemplate < ActiveRecord::Migration + def up + GsParameter.where(:entity => 'sofia', :section => 'profile:gemeinschaft').each do |profile| + profile.update_attributes(:section => 'profile') + end + end + + def down + GsParameter.where(:entity => 'sofia', :section => 'profile').each do |profile| + profile.update_attributes(:section => 'profile:gemeinschaft') + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 7bae5fd..fc2b635 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130128121800) do +ActiveRecord::Schema.define(:version => 20130212071000) do create_table "access_authorizations", :force => true do |t| t.string "access_authorizationable_type" @@ -124,6 +124,16 @@ ActiveRecord::Schema.define(:version => 20130128121800) do t.string "music" end + create_table "backup_jobs", :force => true do |t| + t.datetime "started_at" + t.datetime "finished_at" + t.string "state" + t.string "directory" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "backup_file" + end + create_table "call_forward_cases", :force => true do |t| t.string "value" t.datetime "created_at", :null => false @@ -358,6 +368,7 @@ ActiveRecord::Schema.define(:version => 20130128121800) do t.string "locked_by" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.string "queue" end add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" @@ -540,6 +551,7 @@ ActiveRecord::Schema.define(:version => 20130128121800) do t.string "default_area_code" t.string "default_company_name" t.string "default_system_email" + t.string "trunk_access_code" end create_table "gs_cluster_sync_log_entries", :force => true do |t| @@ -634,6 +646,28 @@ ActiveRecord::Schema.define(:version => 20130128121800) do t.string "hostname", :limit => 256 end + create_table "intruders", :force => true do |t| + t.string "list_type" + t.string "key" + t.integer "points" + t.integer "bans" + t.datetime "ban_last" + t.datetime "ban_end" + t.string "contact_ip" + t.integer "contact_port" + t.integer "contact_count" + t.datetime "contact_last" + t.float "contacts_per_second" + t.float "contacts_per_second_max" + t.string "user_agent" + t.string "to_user" + t.string "comment" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "intruders", ["key"], :name => "index_intruders_on_key", :unique => true + create_table "languages", :force => true do |t| t.string "name" t.string "code" @@ -939,15 +973,9 @@ ActiveRecord::Schema.define(:version => 20130128121800) do t.datetime "updated_at", :null => false t.integer "sip_account_id" t.integer "softkey_function_id" - t.integer "call_forward_id" t.string "uuid" - end - - create_table "system_messages", :force => true do |t| - t.integer "user_id" - t.string "content" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "softkeyable_type" + t.integer "softkeyable_id" end create_table "tasks", :id => false, :force => true do |t| diff --git a/lib/freeswitch_event.rb b/lib/freeswitch_event.rb index b6e5cbc..68d9df2 100644 --- a/lib/freeswitch_event.rb +++ b/lib/freeswitch_event.rb @@ -44,8 +44,8 @@ class FreeswitchEventSocket @socket.close end - def read() - return @socket.recv(1024) + def read(read_bytes=1024) + return @socket.recv(read_bytes) end def result() @@ -130,4 +130,20 @@ class FreeswitchAPI return false end + + def self.channel_variable_get(channel_uuid, variable_name) + result = nil + event = FreeswitchEventSocket.new() + if event && event.connect() + event.command( "api uuid_getvar #{channel_uuid} #{variable_name}") + event_result = event.result() + if event_result && event_result["Content-Type"] == 'api/response' && event_result["Content-Length"].to_i > 0 + result = event.read(event_result["Content-Length"].to_i) + end + event.close() + end + + return result + end + end diff --git a/lib/tasks/backup.rake b/lib/tasks/backup.rake new file mode 100644 index 0000000..c285e1f --- /dev/null +++ b/lib/tasks/backup.rake @@ -0,0 +1,6 @@ +namespace :backup do + desc "Backup the system" + task :daily_backup => :environment do + # This would be the daily backup. + end +end
\ No newline at end of file diff --git a/lib/tasks/cvs_user_import.rake b/lib/tasks/csv_user_import.rake index 81959d5..81959d5 100644 --- a/lib/tasks/cvs_user_import.rake +++ b/lib/tasks/csv_user_import.rake diff --git a/lib/tasks/gs_cluster.rake b/lib/tasks/gs_cluster.rake index 7b49ebb..c248c32 100644 --- a/lib/tasks/gs_cluster.rake +++ b/lib/tasks/gs_cluster.rake @@ -201,10 +201,14 @@ namespace :gs_cluster do remote_objects(remote_site, local_node_id, last_sync, Softkey).each do |remote_object| attributes = make_hash(remote_object.attributes) attributes[:sip_account_id] = SipAccount.where(:uuid => attributes[:sip_account_uuid]).first.try(:id) - attributes[:call_forward_id] = CallForward.where(:uuid => attributes[:call_forward_uuid]).first.try(:id) + + if ! attributes[:softkeyable_uuid].blank? + attributes[:softkeyable_id] = attributes[:softkeyable_type].constantize.where(:uuid => attributes[:softkeyable_uuid]).first.try(:id) + end + attributes[:softkey_function_id] = SoftkeyFunction.where(:name => attributes[:function]).first.try(:id) attributes.delete(:sip_account_uuid) - attributes.delete(:call_forward_uuid) + attributes.delete(:softkeyable_uuid) attributes.delete(:softkey_function) process_object(Softkey, Softkey, Softkey.where(:uuid => attributes[:uuid]).first, attributes) end diff --git a/misc/freeswitch/conf/freeswitch.xml b/misc/freeswitch/conf/freeswitch.xml index fd6ab67..a5fe873 100644 --- a/misc/freeswitch/conf/freeswitch.xml +++ b/misc/freeswitch/conf/freeswitch.xml @@ -466,6 +466,470 @@ </macros> </phrases> </language> + <language name="de" say-module="de" sound-prefix="/opt/freeswitch/sounds/de/de/callie"> + <phrases> + <macros> + <macro name="voicemail_hello"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-hello.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_enter_id"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-enter_id.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_enter_pass"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-enter_pass.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_fail_auth"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-fail_auth.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_goodbye"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-goodbye.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_abort"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-abort.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_message_count"> + <input pattern="^(1):(.*)$" break_on_match="true"> + <match> + <action function="play-file" data="voicemail/vm-you_have.wav"/> + <action function="say" data="$1" method="pronounced" type="items"/> + <action function="play-file" data="voicemail/vm-$2.wav"/> + <action function="play-file" data="voicemail/vm-message.wav"/> + </match> + </input> + <input pattern="^(\d+):(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-you_have.wav"/> + <action function="say" data="$1" method="pronounced" type="items"/> + <action function="play-file" data="voicemail/vm-$2.wav"/> + <action function="play-file" data="voicemail/vm-messages.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_menu"> + <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-listen_new.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-listen_saved.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-advanced.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$3" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-to_exit.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$4" method="pronounced" type="name_phonetic"/> + </match> + </input> + </macro> + <macro name="voicemail_config_menu"> + <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-to_record_greeting.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-choose_greeting.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-record_name2.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$3" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-change_password.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$4" method="pronounced" type="name_spelled"/> + <action function="execute" data="sleep(100)"/> + <action function="play-file" data="voicemail/vm-main_menu.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$5" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_record_name"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-record_name1.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_record_file_check"> + <input pattern="^([0-9#*]):([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-save_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$3" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-rerecord.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_record_urgent_check"> + <input pattern="^([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-mark-urgent.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-continue.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_forward_prepend"> + <input pattern="^([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-forward_add_intro.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-send_message_now.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_forward_message_enter_extension"> + <input pattern="^([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/> + <action function="play-file" data="voicemail/vm-followed_by.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_invalid_extension"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_listen_file_check"> + <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-save_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-delete_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$3" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-forward_to_email.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$4" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-return_call.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$5" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-to_forward.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$6" method="pronounced" type="name_spelled"/> + </match> + </input> + <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$"> + <match> + <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-save_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-delete_recording.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$3" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-return_call.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$5" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-to_forward.wav"/> + <action function="play-file" data="voicemail/vm-press.wav"/> + <action function="say" data="$6" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_choose_greeting"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_choose_greeting_fail"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_record_greeting"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-record_greeting.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_record_message"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-record_message.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_greeting_selected"> + <input pattern="^(\d+)$"> + <match> + <action function="play-file" data="voicemail/vm-greeting.wav"/> + <action function="say" data="$1" method="pronounced" type="items"/> + <action function="play-file" data="voicemail/vm-selected.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_play_greeting"> + <input pattern="^(\d+)$"> + <match> + <action function="play-file" data="voicemail/vm-person.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + <action function="play-file" data="voicemail/vm-not_available.wav"/> + </match> + </input> + <input pattern="^name:(.+)$"> + <match> + <action function="play-file" data="$1"/> + <action function="play-file" data="voicemail/vm-not_available.wav"/> + </match> + </input> + <input pattern="^greeting:(.+)$"> + <match> + <action function="play-file" data="$1"/> + </match> + </input> + </macro> + <macro name="voicemail_say_number"> + <input pattern="^(\d+)$"> + <match> + <action function="say" data="$1" method="pronounced" type="items"/> + </match> + </input> + </macro> + <macro name="voicemail_say_message_number"> + <input pattern="^([a-z]+):(\d+)$"> + <match> + <action function="play-file" data="voicemail/vm-$1.wav"/> + <action function="play-file" data="voicemail/vm-message_number.wav"/> + <action function="say" data="$2" method="pronounced" type="items"/> + </match> + </input> + </macro> + <macro name="voicemail_say_phone_number"> + <input pattern="^(.*)$"> + <match> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_say_name"> + <input pattern="^(.*)$"> + <match> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="voicemail_ack"> + <input pattern="^(too-small)$"> + <match> + <action function="play-file" data="voicemail/vm-too-small.wav"/> + </match> + </input> + <input pattern="^(deleted)$"> + <match> + <action function="play-file" data="voicemail/vm-message.wav"/> + <action function="play-file" data="voicemail/vm-$1.wav"/> + </match> + </input> + <input pattern="^(saved)$"> + <match> + <action function="play-file" data="voicemail/vm-message.wav"/> + <action function="play-file" data="voicemail/vm-saved2.wav"/> + </match> + </input> + <input pattern="^(emailed)$"> + <match> + <action function="play-file" data="voicemail/vm-message.wav"/> + <action function="play-file" data="voicemail/vm-$1.wav"/> + </match> + </input> + <input pattern="^(marked-urgent)$"> + <match> + <action function="play-file" data="voicemail/vm-message.wav"/> + <action function="play-file" data="voicemail/vm-$1.wav"/> + </match> + </input> + </macro> + <macro name="voicemail_say_date"> + <input pattern="^(.*)$"> + <match> + <action function="say" data="$1" method="pronounced" type="current_date_time"/> + </match> + </input> + </macro> + <macro name="voicemail_disk_quota_exceeded"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="voicemail/vm-mailbox_full.wav"/> + </match> + </input> + </macro> + <macro name="valet_announce_ext"> + <input pattern="^([^\:]+):(.*)$"> + <match> + <action function="say" data="$2" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> + <macro name="valet_lot_full"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/> + </match> + </input> + </macro> + <macro name="valet_lot_empty"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/> + </match> + </input> + </macro> + <macro name="logged_in"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_now_logged_in.wav"/> + </match> + </input> + </macro> + <macro name="logged_out"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_now_logged_out.wav"/> + </match> + </input> + </macro> + <macro name="acd_announce_position_enter"> + <input pattern="^([0-9]+)$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_number.wav"/> + <action function="say" data="$1" method="pronounced" type="number"/> + <action function="play-file" data="ivr/ivr-in_line.wav"/> + </match> + </input> + </macro> + <macro name="acd_announce_position_change"> + <input pattern="^1$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_number.wav"/> + <action function="say" data="1" method="pronounced" type="number"/> + <action function="play-file" data="ivr/ivr-in_line.wav"/> + <action function="break"/> + </match> + </input> + <input pattern="^([0-9]+)$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_number.wav"/> + <action function="say" data="$1" method="pronounced" type="number"/> + <action function="play-file" data="ivr/ivr-in_line.wav"/> + <action function="play-file" data="ivr/ivr-thank_you_for_holding.wav"/> + </match> + </input> + </macro> + <macro name="acd_announce_position_periodic"> + <input pattern="^1$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_number.wav"/> + <action function="say" data="1" method="pronounced" type="number"/> + <action function="play-file" data="ivr/ivr-in_line.wav"/> + <action function="break"/> + </match> + </input> + <input pattern="^([0-9]+)$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_number.wav"/> + <action function="say" data="$1" method="pronounced" type="number"/> + <action function="play-file" data="ivr/ivr-in_line.wav"/> + <action function="play-file" data="ivr/ivr-thank_you_for_holding.wav"/> + </match> + </input> + </macro> + <macro name="acd_announce_call_agents"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="$1"/> + </match> + </input> + </macro> + <macro name="acd_greeting"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="$1"/> + </match> + </input> + </macro> + <macro name="acd_goodbye"> + <input pattern="^(.*)$"> + <match> + <action function="play-file" data="$1"/> + </match> + </input> + </macro> + <macro name="acd_agent_status"> + <input pattern="^active$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_now_logged_in.wav"/> + </match> + </input> + <input pattern="^inactive$"> + <match> + <action function="play-file" data="ivr/ivr-you_are_now_logged_out.wav"/> + </match> + </input> + </macro> + </macros> + </phrases> + </language> </section> <section name="configuration" description="Gemeinschaft5 FreeSwitch configuration"> <configuration name="acl.conf" description="Network Lists"> @@ -632,6 +1096,7 @@ <load module="mod_local_stream"/> <load module="mod_tone_stream"/> <load module="mod_say_en"/> + <load module="mod_say_de"/> <load module="mod_spandsp"/> <load module="mod_snmp"/> <load module="mod_dingaling"/> @@ -639,6 +1104,7 @@ </configuration> <configuration name="lua.conf" description="LUA Configuration"> <settings> + <param name="module-directory" value="/usr/lib/i386-linux-gnu/lua/5.1/?.so;"/> <param name="script-directory" value="/usr/share/freeswitch/scripts/?.lua;/usr/share/lua/5.1/?.lua;"/> <param name="xml-handler-script" value="configuration.lua"/> <param name="xml-handler-bindings" value="directory|configuration"/> diff --git a/misc/freeswitch/scripts/common/database.lua b/misc/freeswitch/scripts/common/database.lua index 1f39135..345f69d 100644 --- a/misc/freeswitch/scripts/common/database.lua +++ b/misc/freeswitch/scripts/common/database.lua @@ -16,6 +16,7 @@ function Database.new(self, arg) self.class = 'database'; self.log = arg.log; self.conn = nil; + self.ignore_on_update = arg.ignore_on_update or {}; return object; end @@ -71,6 +72,45 @@ function Database.last_insert_id(self) end +function Database.insert_or_update(self, db_table, record, use_on_update) + ignore_on_update = ignore_on_update or self.ignore_on_update; + local record_sql_create = {}; + local record_sql_update = {}; + + for key, value in pairs(record) do + if ignore_on_update[key] ~= false then + table.insert(record_sql_update, self:key_value(key, value)); + end + table.insert(record_sql_create, self:key_value(key, value)); + end + + local sql_query = 'INSERT INTO `' .. db_table .. '` SET ' .. table.concat(record_sql_create, ', ') .. ' ON DUPLICATE KEY UPDATE ' .. table.concat(record_sql_update, ', '); + + return self:query(sql_query); +end + + +function Database.key_value(self, key, value) + return self:escape(key, '`') .. ' = ' .. self:escape(value, '"'); +end + + +function Database.escape(self, value, str_quotes) + str_quotes = str_quotes or ''; + if type(value) == 'boolean' then + return tostring(value):upper(); + elseif type(value) == 'number' then + return tostring(value); + elseif type(value) == 'string' then + return str_quotes .. value:gsub('"', '\\"'):gsub("'", "\\'") .. str_quotes; + elseif type(value) == 'table' and value.raw then + return tostring(value[1]); + else + return 'NULL'; + end +end + + function Database.release(self) if self.conn then self.conn:release(); diff --git a/misc/freeswitch/scripts/common/fapi.lua b/misc/freeswitch/scripts/common/fapi.lua index 5b96633..b749a69 100644 --- a/misc/freeswitch/scripts/common/fapi.lua +++ b/misc/freeswitch/scripts/common/fapi.lua @@ -32,8 +32,10 @@ function FApi.return_result(self, result, positive, negative, unspecified) return negative; elseif result:match('^+OK') then return positive; - else + elseif type(unspecified) ~= 'nil' then return unspecified; + else + return result; end end @@ -75,6 +77,7 @@ function FApi.create_uuid(self, uuid) end function FApi.execute(self, function_name, function_parameters) + function_parameters = function_parameters or ''; local result = self.fs_api:execute(function_name, function_parameters); return self:return_result(result, true); end diff --git a/misc/freeswitch/scripts/common/intruder.lua b/misc/freeswitch/scripts/common/intruder.lua new file mode 100644 index 0000000..083ec37 --- /dev/null +++ b/misc/freeswitch/scripts/common/intruder.lua @@ -0,0 +1,51 @@ +-- Gemeinschaft 5 module: intruder class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + + +Intruder = {} + + +function Intruder.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'intruder' + self.database = arg.database; + + return object; +end + + +function Intruder.update_blacklist(self, event) + local intruder_record = { + list_type = 'blacklist', + key = event.key, + points = event.points, + bans = event.record.banned, + contact_ip = event.received_ip, + contact_port = event.received_port, + contact_count = event.record.contact_count + 1, + contact_last = { 'FROM_UNIXTIME(' .. tostring(math.floor(event.timestamp/1000000)) .. ')', raw = true }, + contacts_per_second = event.contacts_per_second, + contacts_per_second_max = event.contacts_per_second_max, + user_agent = event.user_agent, + to_user = event.to_user, + comment = 'Permimeter', + created_at = {'NOW()', raw = true }, + updated_at = {'NOW()', raw = true }, + }; + + if tonumber(event.ban_time) then + intruder_record.ban_last = { 'FROM_UNIXTIME(' .. event.ban_time .. ')', raw = true }; + end + if tonumber(event.ban_end) then + intruder_record.ban_end = { 'FROM_UNIXTIME(' .. event.ban_end .. ')', raw = true }; + end + + self.database:insert_or_update('intruders', intruder_record, { created_at = false, comment = false }); +end diff --git a/misc/freeswitch/scripts/common/perimeter.lua b/misc/freeswitch/scripts/common/perimeter.lua new file mode 100644 index 0000000..0815d33 --- /dev/null +++ b/misc/freeswitch/scripts/common/perimeter.lua @@ -0,0 +1,241 @@ +-- Gemeinschaft 5 module: perimeter class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + + +Perimeter = {} + + +function Perimeter.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'perimeter' + self.database = arg.database; + self.domain = arg.domain; + self.sources = {}; + + self.checks_available = { + check_frequency = self.check_frequency, + check_username_scan = self.check_username_scan, + check_bad_headers = self.check_bad_headers, + }; + + return object; +end + + +function Perimeter.setup(self, event) + require 'common.configuration_table'; + local config = common.configuration_table.get(self.database, 'perimeter'); + + self.contact_count_threshold = 10; + self.contact_span_threshold = 2; + self.name_changes_threshold = 2; + self.blacklist_file = '/var/opt/gemeinschaft/firewall/blacklist'; + self.blacklist_file_comment = '# PERIMETER_BAN - points: {points}, generated: {date}'; + self.blacklist_file_entry = '{received_ip} udp 5060'; + self.ban_command = 'sudo /sbin/service shorewall refresh'; + self.ban_threshold = 20; + self.ban_tries = 1; + self.checks = { register = {}, call = {} }; + self.bad_headers = { register = {}, call = {} }; + + if config and config.general then + for key, value in pairs(config.general) do + self[key] = value; + end + end + + self.checks.register = config.checks_register or {}; + self.checks.call = config.checks_call or {}; + self.bad_headers.register = config.bad_headers_register; + self.bad_headers.call = config.bad_headers_call; + + self.log:info('[perimeter] PERIMETER - setup perimeter defense'); +end + + +function Perimeter.record_load(self, event) + if not self.sources[event.key] then + self.sources[event.key] = { + contact_first = event.timestamp, + contact_last = event.timestamp, + contact_count = 0, + span_contact_count = 0, + span_start = event.timestamp, + points = 0, + banned = 0, + }; + end + + return self.sources[event.key]; +end + + +function Perimeter.format_date(self, value) + local epoch = tonumber(tostring(value/1000000):match('^(%d-)%.')); + return os.date('%Y-%m-%d %X', tonumber(epoch)) .. '.' .. (value-(epoch*1000000)); +end + + +function Perimeter.record_update(self, event) + event.record.contact_last = event.timestamp; + event.record.contact_count = event.record.contact_count + 1; + event.record.points = event.points or event.record.points; + event.record.span_start = event.span_start or event.record.span_start; + event.record.span_contact_count = (event.span_contact_count or event.record.span_contact_count) + 1; + event.record.users = event.users or event.record.users; +end + + +function Perimeter.check(self, event) + if not event or not event.key then + self.log:warning('[perimeter] PERIMETER_CHECK - no event/key'); + return; + end + + event.record = self:record_load(event); + if event.record.banned <= self.ban_tries then + for check_name, check_points in pairs(self.checks[event.action]) do + if self.checks_available[check_name] then + local result = self.checks_available[check_name](self, event); + if tonumber(result) then + event.points = (event.points or event.record.points) + result * check_points; + end + end + end + end + + if tonumber(event.points) and event.points < 0 then + event.points = 0; + end + + if event.points then + self.log:info('[', event.key, '/', event.sequence, '] PERIMETER suspicion rising - points: ', event.points,', ', event.action, '=', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host, ', user_agent: ', event.user_agent); + end + + if (event.points or event.record.points) > self.ban_threshold and event.record.banned <= self.ban_tries then + if event.record.banned > 0 and event.record.banned == self.ban_tries then + self.log:warning('[', event.key, '/', event.sequence, '] PERIMETER_BAN_FUTILE - points: ', event.points,', event: ', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host); + else + self.log:notice('[', event.key, '/', event.sequence, '] PERIMETER_BAN - threshold reached: ', event.points,', event: ', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host); + if event.record.banned == 0 then + self:append_blacklist_file(event); + end + self:execute_ban(event); + event.ban_time = os.time(); + end + + event.record.banned = event.record.banned + 1; + event.span_start = event.timestamp; + event.span_contact_count = 0; + event.points = 0; + end + + if event.points then + self:update_intruder(event); + end + + self:record_update(event); +end + + +function Perimeter.check_frequency(self, event) + if event.record.span_contact_count >= self.contact_count_threshold then + self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_FREQUENCY_CHECK - contacts: ', event.record.span_contact_count, ' in < ', (event.timestamp - event.record.span_start)/1000000, ' sec, threshold: ', self.contact_count_threshold, ' in ', self.contact_span_threshold, ' sec'); + event.span_contact_count = 0; + event.span_start = event.timestamp; + event.contacts_per_second = event.record.span_contact_count / ((event.timestamp - event.record.span_start)/1000000) + return 1; + elseif (event.timestamp - event.record.span_start) > (self.contact_span_threshold * 1000000) then + event.span_contact_count = 0; + event.span_start = event.timestamp; + end +end + + +function Perimeter.check_username_scan(self, event) + if not event.to_user then + return; + end + + if not event.record.users or tostring(event.auth_result) == 'SUCCESS' or tostring(event.auth_result) == 'RENEWED' then + event.users = { event.to_user }; + return; + end + + if #event.record.users >= self.name_changes_threshold then + self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_USER_SCAN - user names: ', #event.record.users, ', threshold: ', self.name_changes_threshold); + event.users = {}; + return 1; + else + for index=1, #event.record.users do + if event.record.users[index] == tostring(event.to_user) then + return + end + end + + if not event.users then + event.users = event.record.users or {}; + end + table.insert(event.users, tostring(event.to_user)); + end +end + + +function Perimeter.check_bad_headers(self, event) + local points = nil; + for name, pattern in pairs(self.bad_headers[event.action]) do + pattern = self:expand_variables(pattern, event); + local success, result = pcall(string.find, event[name], pattern); + if success and result then + self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_BAD_HEADERS - ', name, '=', event[name], ' ~= ', pattern); + points = (points or 0) + 1; + end + end + + return points; +end + + +function Perimeter.append_blacklist_file(self, event) + local blacklist = io.open(self.blacklist_file, 'a'); + if not blacklist then + self.log:error('[', event.key, '/', event.sequence, '] PERIMETER_APPEND_BLACKLIST - could not open file: ', self.blacklist_file); + return false; + end + + event.date = self:format_date(event.timestamp); + + if self.blacklist_file_comment then + blacklist:write(self:expand_variables(self.blacklist_file_comment, event), '\n'); + end + + self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_APPEND_BLACKLIST - file: ', self.blacklist_file); + blacklist:write(self:expand_variables(self.blacklist_file_entry, event), '\n'); + blacklist:close(); +end + + +function Perimeter.execute_ban(self, event) + local command = self:expand_variables(self.ban_command, event); + self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_EXECUTE_BAN - command: ', command); + local result = os.execute(command); +end + +function Perimeter.update_intruder(self, event) + require 'common.intruder'; + local result = common.intruder.Intruder:new{ log = self.log, database = self.database }:update_blacklist(event); +end + + +function Perimeter.expand_variables(self, line, variables) + return (line:gsub('{([%a%d%._]+)}', function(captured) + return variables[captured] or ''; + end)) +end diff --git a/misc/freeswitch/scripts/common/sip_account.lua b/misc/freeswitch/scripts/common/sip_account.lua index 8dd432b..d023f20 100644 --- a/misc/freeswitch/scripts/common/sip_account.lua +++ b/misc/freeswitch/scripts/common/sip_account.lua @@ -38,8 +38,12 @@ function SipAccount.find_by_sql(self, where) `a`.`sip_accountable_id`, \ `a`.`hotdeskable`, \ `a`.`gs_node_id`, \ - `b`.`host` \ - FROM `sip_accounts` `a` JOIN `sip_domains` `b` ON `a`.`sip_domain_id` = `b`.`id` \ + `b`.`host`, \ + `c`.`sip_host`, \ + `c`.`profile_name` \ + FROM `sip_accounts` `a` \ + JOIN `sip_domains` `b` ON `a`.`sip_domain_id` = `b`.`id` \ + LEFT JOIN `sip_registrations` `c` ON `a`.`auth_name` = `c`.`sip_user` \ WHERE ' .. where .. ' LIMIT 1'; local sip_account = nil; diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua index 793c191..72ff388 100644 --- a/misc/freeswitch/scripts/common/str.lua +++ b/misc/freeswitch/scripts/common/str.lua @@ -18,6 +18,23 @@ function try(array, arguments) return result; end + +function set(array, arguments, value) + local nop, arguments_count = arguments:gsub('%.', ''); + local structure = array; + arguments:gsub('([^%.]+)', function(entry) + if arguments_count <= 0 then + structure[entry] = value; + elseif type(structure[entry]) == 'table' then + structure = structure[entry]; + else + structure[entry] = {}; + structure = structure[entry]; + end + arguments_count = arguments_count - 1; + end); +end + -- to number function to_n(value) value = tostring(value):gsub('[^%d%.%+%-]', ''); diff --git a/misc/freeswitch/scripts/configuration.lua b/misc/freeswitch/scripts/configuration.lua index 062cf5d..75d0df3 100644 --- a/misc/freeswitch/scripts/configuration.lua +++ b/misc/freeswitch/scripts/configuration.lua @@ -63,7 +63,12 @@ function profile(database, sofia_ini, profile_name, index, domains, node_id) require 'configuration.simple_xml' local xml = configuration.simple_xml.SimpleXml:new(); - local parameters = sofia_ini['profile:' .. profile_name]; + local profile_template = sofia_ini['profile'] or {}; + local parameters = sofia_ini['profile:' .. profile_name] or {}; + + for key, value in pairs(profile_template) do + parameters[key] = parameters[key] or value; + end if not parameters then log:error('SOFIA_PROFILE ', index,' - name: ', profile_name, ' - no parameters'); @@ -134,9 +139,16 @@ function conf_sofia(database) require 'configuration.sip' local domains = configuration.sip.Sip:new{ log = log, database = database}:domains(); - sofia_profiles_xml = ''; + local sofia_profiles = {}; for profile_name, index in pairs(sofia_ini.profiles) do if tonumber(index) and tonumber(index) > 0 then + sofia_profiles[index] = profile_name; + end + end + + local sofia_profiles_xml = ''; + for index, profile_name in ipairs(sofia_profiles) do + if tonumber(index) and tonumber(index) > 0 then sofia_profiles_xml = sofia_profiles_xml .. profile(database, sofia_ini, profile_name, tonumber(index), domains, local_node_id); end end @@ -403,7 +415,7 @@ function directory_sip_account(database) end else require 'common.sip_account' - local sip_account = common.sip_account.SipAccount:new{ log = log, database = database}:find_by_auth_name(auth_name, domain); + local sip_account = common.sip_account.SipAccount:new{ log = log, database = database}:find_by_auth_name(auth_name); require 'common.configuration_table' local user_parameters = common.configuration_table.get(database, 'sip_accounts', 'parameters'); diff --git a/misc/freeswitch/scripts/dialplan/acd.lua b/misc/freeswitch/scripts/dialplan/acd.lua index f4b298e..5ed8979 100644 --- a/misc/freeswitch/scripts/dialplan/acd.lua +++ b/misc/freeswitch/scripts/dialplan/acd.lua @@ -194,7 +194,7 @@ function AutomaticCallDistributor.agents_available(self, strategy) local accounts = {} self.database:query(sql_query, function(entry) - if not entry.callstate then + if common.str.blank(entry.callstate) then table.insert(accounts, entry); end end); diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua index ff4adc6..72503e5 100644 --- a/misc/freeswitch/scripts/dialplan/dialplan.lua +++ b/misc/freeswitch/scripts/dialplan/dialplan.lua @@ -350,10 +350,10 @@ function Dialplan.set_caller_picture(self, entry_id, entry_type, image) require 'dialplan.user' local user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(entry_id); if user then - self.caller:set_variable('sip_h_Call-Info', '<' .. self.user_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(user.record.image) .. '>;purpose=icon'); + self.caller:export_variable('sip_h_Call-Info', '<' .. self.user_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(user.record.image) .. '>;purpose=icon'); end elseif entry_type == 'phonebookentry' and image then - self.caller:set_variable('sip_h_Call-Info', '<' .. self.phone_book_entry_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(image) .. '>;purpose=icon'); + self.caller:export_variable('sip_h_Call-Info', '<' .. self.phone_book_entry_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(image) .. '>;purpose=icon'); end end @@ -445,6 +445,8 @@ function Dialplan.dial(self, destination) send_ringing = ( self.send_ringing_to_gateways and self.caller.from_gateway ), bypass_media_network = self.config.parameters.bypass_media_network, update_callee_display = self.config.parameters.update_callee_display, + detect_dtmf_after_bridge_caller = self.detect_dtmf_after_bridge_caller, + detect_dtmf_after_bridge_callee = self.detect_dtmf_after_bridge_callee, } ); end @@ -759,7 +761,7 @@ function Dialplan.switch(self, destination) elseif not common.str.blank(destination.number) then local result = { continue = false, code = 404, phrase = 'No route' } - local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening'); + local clip_no_screening = common.str.try(self.caller, 'account.record.clip_no_screening'); self.caller.caller_id_numbers = {} if not common.str.blank(clip_no_screening) then for index, number in ipairs(common.str.strip_to_a(clip_no_screening, ',')) do @@ -814,11 +816,13 @@ function Dialplan.switch(self, destination) self.caller:set_callee_id(destination.callee_id_number, destination.callee_id_name); for index, route in ipairs(routes) do - if route.endpoint_type == 'hangup' then - return { continue = false, code = route.endpoint, phrase = route.phrase, cause = route.value } + if route.type == 'hangup' then + self.log:notice('SWITCH_HANGUP - code: ', route.code, ', phrase: ', route.phrase, ', cause: ', route.cause); + return { continue = false, code = route.code or '404', phrase = route.phrase, cause = route.cause } end - if route.endpoint_type == 'forward' then - return { continue = true, call_forwarding = { number = route.value, service = 'route', type = 'phonenumber' }} + if route.type == 'forward' then + self.log:notice('SWITCH_CALL_FORWARDING - number: ', route.number); + return { continue = true, call_forwarding = { number = route.number, service = 'route', type = 'phonenumber' }} end for key, value in pairs(route) do diff --git a/misc/freeswitch/scripts/dialplan/dtmf.lua b/misc/freeswitch/scripts/dialplan/dtmf.lua new file mode 100644 index 0000000..4dbd35f --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/dtmf.lua @@ -0,0 +1,69 @@ +-- Gemeinschaft 5 module: dtmf class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + +Dtmf = {} + +-- create dtmf object +function Dtmf.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'Dtmf'; + self.log = arg.log; + self.bleg = arg.bleg + self.digit_timeout = arg.digit_timeout or 5; + self.router = arg.router; + + return object; +end + + +function Dtmf.detect(self, caller, sequence, digit, duration, calee) + local timestamp = os.time(); + if timestamp - sequence.updated > self.digit_timeout then + sequence.digits = digit; + else + sequence.digits = sequence.digits .. digit; + end + + caller.dtmf_digits = sequence.digits; + + if calee then + self.log:debug('DTMF_RECEIVER callee - digit: [', digit, '][', duration, '], sequence: ', sequence.digits); + else + self.log:debug('DTMF_RECEIVER caller - digit: [', digit, '][', duration, '], sequence: ', sequence.digits); + end + + local route = self.router:route_run('dtmf', true); + sequence.updated = timestamp; + + if not route then + return; + end + + if route.type == 'dialplanfunction' or route.type == 'phonenumber' or route.type == 'unknown' then + self:transfer(caller, route.destination_number, calee) + else + self.log:notice('DTMF_RECEIVER - unhandled destination: ', route.type, '=', route.id); + end +end + + +function Dtmf.transfer(self, caller, destination, calee) + require 'common.fapi' + local fapi = common.fapi.FApi:new{ log = log }; + local callee_uuid = caller:to_s('bridge_to'); + + self.log:notice('DTMF_RECEIVER_TRANSFER - destination: ', destination, ', uuid: ', caller.uuid, ', callee_uuid: ', callee_uuid, ', callee_initiated: ', calee); + if calee then + caller:execute('transfer', destination); + fapi:execute('uuid_kill', callee_uuid); + else + fapi:execute('uuid_transfer', callee_uuid .. ' ' .. destination); + caller.session:hangup(); + end +end diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua index 2ca51c8..4430be1 100644 --- a/misc/freeswitch/scripts/dialplan/functions.lua +++ b/misc/freeswitch/scripts/dialplan/functions.lua @@ -111,6 +111,8 @@ function Functions.dialplan_function(self, caller, dialed_number) result = "+" .. tostring(parameters[3]); elseif fid == "hangup" then result = self:hangup(caller, parameters[3], parameters[4]); + elseif fid == "park" then + result = self:park(caller, parameters[3]); end return result; @@ -264,7 +266,7 @@ function Functions.account_node_change(self, caller) -- resync caller phones for index, phone_caller in ipairs(caller_phones) do - local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host }; self.log:info('NODE_CHANGE - resync phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); end @@ -302,6 +304,7 @@ function Functions.user_login(self, caller, number, pin) if not caller_phone then self.log:notice('LOGIN - caller phone not found or not hot-deskable'); + local result = phone_class:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host }; return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true } end @@ -374,13 +377,13 @@ function Functions.user_login(self, caller, number, pin) -- resync destination phones for index, phone_destination in ipairs(destination_phones) do - local result = phone_destination:resync{ auth_name = destination_sip_account.auth_name, domain = caller.domain_local }; + local result = phone_destination:resync{ auth_name = destination_sip_account.record.auth_name, domain = destination_sip_account.record.host }; self.log:info('LOGIN - resync destination phone - mac: ', phone_destination.record.mac_address, ', ip_address: ', phone_destination.record.ip_address, ', result: ', result); end -- resync caller phones for index, phone_caller in ipairs(caller_phones) do - local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host }; self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); end @@ -409,8 +412,9 @@ function Functions.user_logout(self, caller) local caller_phones = phone_class:find_all_hot_deskable_by_account(caller_sip_account.id); - if caller_phones == 0 then + if #caller_phones == 0 then self.log:notice('LOGOUT - caller phones not found or not hot-deskable'); + local result = phone_class:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host }; return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true } end @@ -426,7 +430,7 @@ function Functions.user_logout(self, caller) -- resync caller phones for index, phone_caller in ipairs(caller_phones) do - local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain }; + local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host }; self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result); end @@ -909,3 +913,9 @@ function Functions.hangup(self, caller, code, phrase) self.log:info("FUNCTION_HANGUP code: ", code, ', phrase: ', phrase); return { continue = false, code = code, phrase = phrase:gsub('_', ' '), no_cdr = true } end + +function Functions.park(self, caller, lot) + self.log:info("FUNCTION_PARK lot: ", lot); + caller:execute("valet_park", 'valet_lot ' .. lot); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end diff --git a/misc/freeswitch/scripts/dialplan/hunt_group.lua b/misc/freeswitch/scripts/dialplan/hunt_group.lua index 2c73bf8..fa3c05b 100644 --- a/misc/freeswitch/scripts/dialplan/hunt_group.lua +++ b/misc/freeswitch/scripts/dialplan/hunt_group.lua @@ -98,6 +98,18 @@ function HuntGroup.run(self, dialplan_object, caller, destination) self.log:info('HUNTGROUP ', self.record.id, ' - name: ', self.record.name, ', strategy: ', self.record.strategy,', members: ', #hunt_group_members); + local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening'); + caller.caller_id_numbers = {} + if not common.str.blank(clip_no_screening) then + for index, number in ipairs(common.str.strip_to_a(clip_no_screening, ',')) do + table.insert(caller.caller_id_numbers, number); + end + end + for index, number in ipairs(caller.caller_phone_numbers) do + table.insert(caller.caller_id_numbers, number); + end + self.log:info('CALLER_ID_NUMBERS - clir: ', caller.clir, ', numbers: ', table.concat(caller.caller_id_numbers, ',')); + local save_destination = caller.destination; local destinations = {} @@ -172,6 +184,7 @@ function HuntGroup.run(self, dialplan_object, caller, destination) self.log:info('HUNTGROUP ', self.record.id, ' - all members busy'); run_queue = false; end + caller:sleep(500); end else if forwarding_destination then diff --git a/misc/freeswitch/scripts/dialplan/router.lua b/misc/freeswitch/scripts/dialplan/router.lua index cdcb58b..bda80a7 100644 --- a/misc/freeswitch/scripts/dialplan/router.lua +++ b/misc/freeswitch/scripts/dialplan/router.lua @@ -18,11 +18,16 @@ function Router.new(self, arg) self.routes = arg.routes or {}; self.caller = arg.caller; self.variables = arg.variables or {}; + self.routing_tables = {}; return object; end -function Router.read_table(self, table_name) +function Router.read_table(self, table_name, force_reload) + if not force_reload and self.routing_tables[table_name] then + return self.routing_tables[table_name]; + end + local routing_table = {}; local sql_query = 'SELECT * \ @@ -48,6 +53,8 @@ function Router.read_table(self, table_name) }); end); + self.routing_tables[table_name] = routing_table; + return routing_table; end @@ -143,7 +150,7 @@ function Router.route_match(self, route) if not common.str.blank(element.var_out) then local command, variable_name = common.str.partition(element.var_out, ':'); if not command or not variable_name or command == 'var' then - destination[element.var_out] = replacement; + common.str.set(destination, element.var_out, replacement); elseif command == 'chv' then destination.channel_variables[variable_name] = replacement; elseif command == 'hdr' then @@ -159,6 +166,7 @@ function Router.route_match(self, route) end if route_matches then + destination.number = destination.number or destination.destination_number; return destination; end; diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua index d1557e9..b56f1b2 100644 --- a/misc/freeswitch/scripts/dialplan/sip_call.lua +++ b/misc/freeswitch/scripts/dialplan/sip_call.lua @@ -95,39 +95,50 @@ function SipCall.fork(self, destinations, arg ) table.insert(origination_variables, 'ignore_display_updates=true'); end - if not destination.node_local then + if not destination.node_local or destination.type == 'node' then require 'common.node' - local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id); - if node then - table.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id); - table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number); + local node = nil; + + if not destination.node_local then + node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id); + else + node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.id); end - elseif destination.type == 'node' then - local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.id); if node then table.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id); + table.insert(origination_variables, 'sip_h_X-GS_account_uuid=' .. tostring(self.caller.account_uuid)); + table.insert(origination_variables, 'sip_h_X-GS_account_type=' .. tostring(self.caller.account_type)); + table.insert(origination_variables, 'sip_h_X-GS_auth_account_type=' .. tostring(self.caller.auth_account_type)); + table.insert(origination_variables, 'sip_h_X-GS_auth_account_uuid=' .. tostring(self.caller.auth_account_uuid)); + table.insert(origination_variables, 'sip_h_X-GS_loop_count=' .. tostring(self.caller.loop_count)); table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number); end elseif destination.type == 'sipaccount' then local callee_id_params = ''; local sip_account = sip_account_class:find_by_id(destination.id); - local call_waiting = self:call_waiting_busy(sip_account); - if not call_waiting then - destinations[index].numbers = sip_account:phone_numbers(); + if not sip_account then + self.log:notice('FORK - sip_account not found - sip_account=', destination.id); + elseif common.str.blank(sip_account.record.profile_name) or common.str.blank(sip_account.record.sip_host) then + call_result = { code = 480, phrase = 'User offline', disposition = 'USER_NOT_REGISTERED' }; + else + local call_waiting = self:call_waiting_busy(sip_account); + if not call_waiting then + destinations[index].numbers = sip_account:phone_numbers(); - if not arg.callee_id_name then - table.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'"); - end - if not arg.callee_id_number then - table.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'"); - end - if destination.alert_info then - table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'"); + if not arg.callee_id_name then + table.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'"); + end + if not arg.callee_id_number then + table.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'"); + end + if destination.alert_info then + table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'"); + end + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/' .. sip_account.record.profile_name .. '/' .. sip_account.record.auth_name .. '%' .. sip_account.record.sip_host); + else + some_destinations_busy = true; + call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' }; end - table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']user/' .. sip_account.record.auth_name); - else - some_destinations_busy = true; - call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' }; end elseif destination.type == 'gateway' then require 'common.gateway' @@ -169,11 +180,6 @@ function SipCall.fork(self, destinations, arg ) end self.caller:set_callee_id(arg.callee_id_number, arg.callee_id_name); - self.caller:set_header('X-GS_account_uuid', self.caller.account_uuid); - self.caller:set_header('X-GS_account_type', self.caller.account_type); - self.caller:set_header('X-GS_auth_account_type', self.caller.auth_account_type); - self.caller:set_header('X-GS_auth_account_uuid', self.caller.auth_account_uuid); - self.caller:set_header('X-GS_loop_count', self.caller.loop_count); self.caller:set_variable('call_timeout', arg.timeout ); self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout); @@ -195,6 +201,12 @@ function SipCall.fork(self, destinations, arg ) fork_index = tonumber(session_callee:getVariable('gs_fork_index')) or 0; local destination = destinations[fork_index]; + if arg.detect_dtmf_after_bridge_caller then + session:execute('start_dtmf'); + end + if arg.detect_dtmf_after_bridge_callee then + session_callee:execute('start_dtmf'); + end if arg.bypass_media_network then local callee_uuid = session_callee:get_uuid(); @@ -226,10 +238,15 @@ function SipCall.fork(self, destinations, arg ) self.caller:set_variable('gs_destination_id', destination.id); self.caller:set_variable('gs_destination_uuid', destination.uuid); + if arg.detect_dtmf_after_bridge_callee then + session_callee:setInputCallback('input_call_back_callee', 'session_callee'); + end + self.log:info('FORK ', fork_index, ' BRIDGE - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id, ', number: ', destination.number, ', dial_time: ', os.time() - start_time); + freeswitch.bridge(self.caller.session, session_callee); self:wait_hangup(self.caller.session, session_callee); end diff --git a/misc/freeswitch/scripts/dialplan_default.lua b/misc/freeswitch/scripts/dialplan_default.lua index 7caff57..8fb9057 100644 --- a/misc/freeswitch/scripts/dialplan_default.lua +++ b/misc/freeswitch/scripts/dialplan_default.lua @@ -8,13 +8,28 @@ function hangup_hook_caller(s, status, arg) if tostring(status) == 'transfer' then if start_caller and start_caller.destination then log:info('CALL_TRANSFERRED - destination was: ', start_caller.destination.type, '=', start_caller.destination.id,', number: ' .. tostring(start_caller.destination.number) .. ', to: ' .. start_caller:to_s('sip_refer_to')); - start_caller.auth_account = start_dialplan:object_find(start_caller.destination.type, start_caller.destination.id); + start_caller.auth_account = start_caller.dialplan:object_find(start_caller.destination.type, start_caller.destination.id); start_caller.forwarding_number = start_caller.destination.number; start_caller.forwarding_service = 'transfer'; end end end +function input_call_back_caller(s, object_type, object_data, arg) + if object_type == 'dtmf' then + require 'dialplan.dtmf' + local dtmf = dialplan.dtmf.Dtmf:new{ log = log, router = dtmf_router }:detect(start_caller, start_caller.dtmf, object_data.digit, object_data.duration); + end +end + +function input_call_back_callee(s, object_type, object_data, arg) + if object_type == 'dtmf' then + require 'dialplan.dtmf' + local dtmf = dialplan.dtmf.Dtmf:new{ log = log, router = dtmf_router }:detect(start_caller, start_caller.dtmf_callee, object_data.digit, object_data.duration, true); + end +end + + -- initialize logging require 'common.log' log = common.log.Log:new{ prefix = '### [' .. session:get_uuid() .. '] ' }; @@ -36,8 +51,17 @@ require 'dialplan.dialplan' local start_dialplan = dialplan.dialplan.Dialplan:new{ log = log, caller = start_caller, database = database }; start_dialplan:configuration_read(); +start_caller.dialplan = start_dialplan; start_caller.local_node_id = start_dialplan.node_id; start_caller:init_channel_variables(); +start_caller.dtmf = { + updated = os.time(), + digits = ''; +}; +start_caller.dtmf_callee = { + updated = os.time(), + digits = ''; +}; if start_dialplan.config.parameters.dump_variables then start_caller:execute('info', 'notice'); @@ -72,6 +96,17 @@ if start_caller.from_node then else start_destination = { type = 'unknown' } start_caller.session:setHangupHook('hangup_hook_caller', 'destination_number'); + + require 'dialplan.router' + dtmf_router = dialplan.router.Router:new{ log = log, database = database, caller = start_caller, variables = start_caller }; + start_dialplan.dtmf_detection = #dtmf_router:read_table('dtmf') > 0; + + if start_dialplan.dtmf_detection then + start_dialplan.detect_dtmf_after_bridge_caller = true; + start_dialplan.detect_dtmf_after_bridge_callee = true; + start_caller.session:setInputCallback('input_call_back_caller', 'start_dialplan'); + end + start_dialplan:run(start_destination); end diff --git a/misc/freeswitch/scripts/event/dump_variables.lua b/misc/freeswitch/scripts/event/dump_variables.lua new file mode 100644 index 0000000..96eb8f7 --- /dev/null +++ b/misc/freeswitch/scripts/event/dump_variables.lua @@ -0,0 +1,52 @@ +-- Gemeinschaft 5 module: dump_variables event handler class +-- (c) AMOOMA GmbH 2012-2013 +-- + +module(...,package.seeall) + + +function handler_class() + return DumpVariables +end + + +DumpVariables = {} + + +function DumpVariables.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'DumpVariables' + self.dump_file = arg.file or '/var/log/freeswitch/variables'; + + return object; +end + + +function DumpVariables.event_handlers(self) + return { CHANNEL_CREATE = { [true] = self.channel_data } } +end + + +function DumpVariables.channel_data(self, event) + local sequence = event:getHeader('Event-Sequence'); + local direction = event:getHeader('Call-Direction'); + + if not direction or direction ~= 'inbound' then + return; + end + + local file = io.open(self.dump_file, 'w'); + if not file then + self.log:error('[', event.sequence, '] DUMP_VARIABLES - could not open file for writing: ', self.dump_file); + return; + end + + self.log:debug('[', event.sequence, '] DUMP_VARIABLES - dumping channel data to: ', self.dump_file); + + file:write(event:serialize(), '\n'); + file:close(); +end diff --git a/misc/freeswitch/scripts/event/event.lua b/misc/freeswitch/scripts/event/event.lua index 08d8bfe..652fc48 100644 --- a/misc/freeswitch/scripts/event/event.lua +++ b/misc/freeswitch/scripts/event/event.lua @@ -16,29 +16,40 @@ function EventManager.new(self, arg) self.class = 'eventmanager' self.database = arg.database; self.domain = arg.domain; + self.consumer = arg.consumer; return object; end function EventManager.register(self) - self.consumer = freeswitch.EventConsumer('all'); + if not self.consumer then + self.consumer = freeswitch.EventConsumer('all'); + end return (self.consumer ~= nil); end -function EventManager.load_event_modules(self) - require 'common.configuration_table' - self.config = common.configuration_table.get(self.database, 'events'); +function EventManager.load_event_modules(self, modules) + local event_modules = {}; + + for module_name, index in pairs(modules) do + if tonumber(index) and index > 0 then + event_modules[index] = module_name; + self.log:debug('[event] EVENT_MANAGER - enabled handler module: ', module_name); + else + self.log:debug('[event] EVENT_MANAGER - disabled handler module: ', module_name); + end + end - return self.config.modules; + return event_modules; end function EventManager.load_event_handlers(self, event_modules) event_handlers = {} - - for event_module_name, index in pairs(event_modules) do + for index, event_module_name in ipairs(event_modules) do + package.loaded['event.' .. event_module_name] = nil; event_module = require('event.' .. event_module_name); if event_module then self.log:info('[event] EVENT_MANAGER - loading handler module: ', event_module_name); @@ -71,8 +82,12 @@ end function EventManager.run(self) + require 'common.configuration_table' + self.config = common.configuration_table.get(self.database, 'events'); + + local event_modules = self:load_event_modules(self.config.modules); + self.log:info('[event] EVENT_MANAGER_START - handler modules: ', #event_modules); - local event_modules = self:load_event_modules(); local event_handlers = self:load_event_handlers(event_modules); if not event_handlers then @@ -104,4 +119,6 @@ function EventManager.run(self) end end end + + self.log:info('[event] EVENT_MANAGER_EXIT - action: ', freeswitch.getGlobalVariable('gs_event_manager')); end diff --git a/misc/freeswitch/scripts/event/perimeter.lua b/misc/freeswitch/scripts/event/perimeter.lua deleted file mode 100644 index 5bbb032..0000000 --- a/misc/freeswitch/scripts/event/perimeter.lua +++ /dev/null @@ -1,107 +0,0 @@ --- Gemeinschaft 5 module: cdr event handler class --- (c) AMOOMA GmbH 2012-2013 --- - -module(...,package.seeall) - - -function handler_class() - return Perimeter -end - - - -Perimeter = {} - -MALICIOUS_CONTACT_COUNT = 20; -MALICIOUS_CONTACT_TIME_SPAN = 2; -BAN_FUTILE = 2; - -function Perimeter.new(self, arg) - arg = arg or {} - object = arg.object or {} - setmetatable(object, self); - self.__index = self; - self.log = arg.log; - self.class = 'cdrsave' - self.database = arg.database; - self.domain = arg.domain; - - self.ip_address_table = {} - self:init(); - - return object; -end - - -function Perimeter.event_handlers(self) - return { CUSTOM = { ['sofia::pre_register'] = self.sofia_pre_register } } -end - - -function Perimeter.init(self) - require 'common.configuration_table'; - local config = common.configuration_table.get(self.database, 'perimeter'); - if config and config.general then - self.malicious_contact_count = tonumber(config.general.malicious_contact_count) or MALICIOUS_CONTACT_COUNT; - self.malicious_contact_time_span = tonumber(config.general.malicious_contact_time_span) or MALICIOUS_CONTACT_TIME_SPAN; - self.ban_futile = tonumber(config.general.ban_futile) or BAN_FUTILE; - self.execute = config.general.execute; - end - - self.log:info('[perimeter] PERIMETER - setup perimeter defense - config: ', self.malicious_contact_count, '/', self.malicious_contact_time_span, ', execute: ', self.execute); -end - - -function Perimeter.sofia_pre_register(self, event) - local ip_address = event:getHeader('network-ip'); - self:check_ip(ip_address); -end - - -function Perimeter.check_ip(self, ip_address) - local event_time = os.time(); - - if not self.ip_address_table[ip_address] then - self.ip_address_table[ip_address] = { last_contact = event_time, contact_count = 0, start_stamp = event_time, banned = 0 } - end - - local ip_record = self.ip_address_table[ip_address]; - ip_record.last_contact = event_time; - ip_record.contact_count = ip_record.contact_count + 1; - - if ip_record.contact_count > MALICIOUS_CONTACT_COUNT then - if (event_time - ip_record.start_stamp) <= MALICIOUS_CONTACT_TIME_SPAN then - self.log:warning('[', ip_address, '] PERIMETER - too many registration attempts'); - ip_record.start_stamp = event_time; - ip_record.contact_count = 0; - if ip_record.banned < BAN_FUTILE then - ip_record.banned = ip_record.banned + 1; - self:ban_ip(ip_address); - else - self.log:error('[', ip_address, '] PERIMETER - ban futile'); - end - end - end -end - - -function Perimeter.ban_ip(self, ip_address) - self.ip_address = ip_address; - - if self.execute then - local command = self:expand_variables(self.execute); - self.log:debug('[', ip_address, '] PERIMETER - execute: ', command); - local result = os.execute(command); - if tostring(result) == '0' then - self.log:warning('[', ip_address, '] PERIMETER - IP banned'); - end - end -end - - -function Perimeter.expand_variables(self, line) - return (line:gsub('{([%a%d_-]+)}', function(captured) - return self[captured]; - end)) -end diff --git a/misc/freeswitch/scripts/event/perimeter_defense.lua b/misc/freeswitch/scripts/event/perimeter_defense.lua new file mode 100644 index 0000000..acdfa8d --- /dev/null +++ b/misc/freeswitch/scripts/event/perimeter_defense.lua @@ -0,0 +1,114 @@ +-- Gemeinschaft 5 module: perimeter defense event handler class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + +function handler_class() + return PerimeterDefense +end + +PerimeterDefense = {} + +function PerimeterDefense.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.log = arg.log; + self.class = 'perimeterdefense' + self.database = arg.database; + self.domain = arg.domain; + + require 'common.perimeter'; + self.perimeter = common.perimeter.Perimeter:new(arg); + self.perimeter:setup(); + + return object; +end + + +function PerimeterDefense.event_handlers(self) + return { + CUSTOM = { + ['sofia::pre_register'] = self.sofia_pre_register, + ['sofia::register_attempt'] = self.sofia_register_attempt, + ['sofia::register_failure'] = self.sofia_register_failure, + }, + CHANNEL_HANGUP = { [true] = self.channel_hangup }, + }; +end + + +function PerimeterDefense.to_register_record(self, event, class) + return { + action = 'register', + class = class, + key = event:getHeader('network-ip'), + sequence = tonumber(event:getHeader('Event-Sequence')), + timestamp = tonumber(event:getHeader('Event-Date-Timestamp')), + received_ip = event:getHeader('network-ip'), + received_port = event:getHeader('network-port'), + from_user = event:getHeader('from-user'), + from_host = event:getHeader('from-host'), + to_user = event:getHeader('to-user'), + to_host = event:getHeader('to-host'), + user_agent = event:getHeader('user-agent'), + username = event:getHeader('username'), + realm = event:getHeader('realm'), + auth_result = event:getHeader('auth-result'), + contact = event:getHeader('contact'), + }; +end + + +function PerimeterDefense.to_call_record(self, event, class) + return { + action = 'call', + class = class, + key = event:getHeader('Caller-Network-Addr'), + sequence = tonumber(event:getHeader('Event-Sequence')), + timestamp = tonumber(event:getHeader('Event-Date-Timestamp')), + received_ip = event:getHeader('Caller-Network-Addr'), + received_port = event:getHeader('variable_sip_network_port'), + hangup_cause = event:getHeader('Hangup-Cause'), + endpoint_disposition = event:getHeader('variable_endpoint_disposition'), + direction = event:getHeader('Call-Direction'), + destination_number = event:getHeader('Caller-Destination-Number'); + caller_id_name = event:getHeader('Caller-Caller-ID-Name'); + caller_id_number = event:getHeader('Caller-Caller-ID-Number'); + from_user = event:getHeader('variable_sip_from_user'), + from_host = event:getHeader('variable_sip_from_host'), + to_user = event:getHeader('variable_sip_to_user'), + to_host = event:getHeader('variable_sip_to_host'), + req_user = event:getHeader('variable_sip_req_user'), + req_host = event:getHeader('variable_sip_req_host'), + user_agent = event:getHeader('variable_sip_user_agent'), + username = event:getHeader('Caller-Username'), + contact = event:getHeader('variable_sip_contact_uri'), + }; +end + + +function PerimeterDefense.sofia_pre_register(self, event) + local record = self:to_register_record(event, 'pre_register'); + self.perimeter:check(record); +end + + +function PerimeterDefense.sofia_register_attempt(self, event) + local record = self:to_register_record(event, 'register_attempt'); + self.perimeter:check(record); +end + + +function PerimeterDefense.sofia_register_failure(self, event) + local record = self:to_register_record(event, 'register_failure'); + self.perimeter:check(record); +end + + +function PerimeterDefense.channel_hangup(self, event) + local record = self:to_call_record(event, 'channel_hangup'); + self.perimeter:check(record); +end diff --git a/misc/freeswitch/scripts/event_manager.lua b/misc/freeswitch/scripts/event_manager.lua index 1e61baf..3991f8f 100644 --- a/misc/freeswitch/scripts/event_manager.lua +++ b/misc/freeswitch/scripts/event_manager.lua @@ -7,12 +7,12 @@ require "common.log" local log = common.log.Log:new() log.prefix = "#E# " -log:info('[event] EVENT_MANAGER start'); +log:info('[event] EVENT_MANAGER_LOADER start'); require 'common.database' local database = common.database.Database:new{ log = log }:connect(); if not database:connected() then - log:error('[event] EVENT_MANAGER - cannot connect to Gemeinschaft database'); + log:error('[event] EVENT_MANAGER_LOADER - cannot connect to Gemeinschaft database'); return; end @@ -23,16 +23,23 @@ local domain = '127.0.0.1'; if domains[1] then domain = domains[1]['host']; else - log:error('[event] EVENT_MANAGER - No SIP domains found!'); + log:error('[event] EVENT_MANAGER_LOADER - No SIP domains found!'); end -require 'event.event' -local event_manager = event.event.EventManager:new{ log = log, database = database, domain = domain } -event_manager:run(); +local event_consumer = nil; +freeswitch.setGlobalVariable('gs_event_manager', 'true'); +while freeswitch.getGlobalVariable('gs_event_manager') ~= 'false' do + package.loaded['event.event'] = nil; + local manager_class = require('event.event'); + local event_manager = manager_class.EventManager:new{ log = log, database = database, domain = domain, consumer = event_consumer }; + freeswitch.setGlobalVariable('gs_event_manager', 'true'); + event_manager:run(); + event_consumer = event_manager.consumer; +end -- ensure database handle is released on exit if database then database:release(); end -log:info('[event] EVENT_MANAGER exit'); +log:info('[event] EVENT_MANAGER_LOADER exit'); diff --git a/misc/freeswitch/scripts/fax_daemon.lua b/misc/freeswitch/scripts/fax_daemon.lua index 94d343a..0784890 100644 --- a/misc/freeswitch/scripts/fax_daemon.lua +++ b/misc/freeswitch/scripts/fax_daemon.lua @@ -5,38 +5,37 @@ local MAIN_LOOP_SLEEP_TIME = 30; -- Set logger -require "common.log" +require 'common.log' local log = common.log.Log:new() -log.prefix = "### [faxdaemon] " +log.prefix = '#F# [faxdaemon] ' -log:debug('Starting fax daemon'); +log:info('FAX_DAEMON start'); -local database = nil; -local api = freeswitch.API(); +require 'common.database' +local database = common.database.Database:new{ log = log }:connect(); +if not database:connected() then + log:error('FAX_DAEMON - cannot connect to Gemeinschaft database'); + return; +end +local api = freeswitch.API(); +require 'dialplan.fax' freeswitch.setGlobalVariable('gs_fax_daemon', 'true'); + while freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' do - require 'common.database' - local database = common.database.Database:new{ log = log }:connect(); - - if not database:connected() then - log:error("connection to Gemeinschaft database lost - retry in " .. MAIN_LOOP_SLEEP_TIME .. " seconds") - else - require 'dialplan.fax' - local fax_documents = dialplan.fax.Fax:new{log=log, database=database}:queued_for_sending(); - - for key, fax_document in pairs(fax_documents) do - if table.getn(fax_document.destination_numbers) > 0 and tonumber(fax_document.retry_counter) > 0 then - log:debug('FAX_DAEMON_LOOP - fax_document=', fax_document.id, '/', fax_document.uuid, ', number: ' .. fax_document.destination_numbers[1]); - local result = api:executeString('luarun send_fax.lua ' .. fax_document.id); - end + local fax_documents = dialplan.fax.Fax:new{log=log, database=database}:queued_for_sending(); + + for key, fax_document in pairs(fax_documents) do + if table.getn(fax_document.destination_numbers) > 0 and tonumber(fax_document.retry_counter) > 0 then + log:debug('FAX_DAEMON_LOOP - fax_document=', fax_document.id, '/', fax_document.uuid, ', number: ' .. fax_document.destination_numbers[1]); + local result = api:executeString('luarun send_fax.lua ' .. fax_document.id); end end - database:release(); - + if freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' then freeswitch.msleep(MAIN_LOOP_SLEEP_TIME * 1000); end end -log:debug('Exiting fax daemon'); +database:release(); +log:info('FAX_DAEMON exit'); diff --git a/misc/freeswitch/scripts/http_request.lua b/misc/freeswitch/scripts/http_request.lua index 1d6f791..a74b4d8 100644 --- a/misc/freeswitch/scripts/http_request.lua +++ b/misc/freeswitch/scripts/http_request.lua @@ -29,7 +29,7 @@ end local success, result, response_headers = http.request{url = url, headers = headers }; -if success then +if success and tostring(result) == '200' then log:debug('HTTP_REQUEST - url: ', url, ', auth: ', tostring(headers.Authorization ~= nil), ', result: ', result); else log:notice('HTTP_REQUEST - url: ', url, ', auth: ', tostring(headers.Authorization ~= nil), ', result: ', result); diff --git a/misc/freeswitch/scripts/phones/phone.lua b/misc/freeswitch/scripts/phones/phone.lua index 6da20f0..57997ba 100644 --- a/misc/freeswitch/scripts/phones/phone.lua +++ b/misc/freeswitch/scripts/phones/phone.lua @@ -115,8 +115,9 @@ end function Phone.resync(self, arg) if not self.model then - self.log:notice('PHONE_RESYNC - unsupported phone model'); - return false; + self.log:notice('PHONE_RESYNC phone model not found - trying Snom resync'); + require 'phones.snom' + return phones.snom.Snom:new{ log = self.log }:resync(arg); end arg.ip_address = arg.ip_address or self.record.ip_address; diff --git a/misc/freeswitch/scripts/send_fax.lua b/misc/freeswitch/scripts/send_fax.lua index 9b6ffce..4898cb8 100644 --- a/misc/freeswitch/scripts/send_fax.lua +++ b/misc/freeswitch/scripts/send_fax.lua @@ -6,9 +6,9 @@ local FAX_FILE_PATH = "/opt/GS5/public/uploads/fax_document/tiff/"; local FAX_ANSWERING_TIMEOUT = 20; -- Set logger -require "common.log" +require 'common.log' local log = common.log.Log:new() -log.prefix = "### [sendfax] " +log.prefix = '#F# [sendfax] ' local document_id = argv[1]; @@ -16,12 +16,12 @@ require 'common.database' local database = common.database.Database:new{ log = log }:connect(); if not database:connected() then - log:error('cannot connect to Gemeinschaft database'); + log:error('FAX_SEND - cannot connect to Gemeinschaft database'); return end if not tonumber(document_id) then - log:error('document id not specified'); + log:error('FAX_SEND - document id not specified'); return end @@ -32,7 +32,7 @@ local fax_class = dialplan.fax.Fax:new(defaults); local fax_document = fax_class:find_document_by_id(document_id); if not fax_document then - log:error('document ' .. document_id .. ' not found'); + log:error('FAX_SEND - document ' .. document_id .. ' not found'); return end @@ -45,14 +45,14 @@ end local fax_account = fax_class:find_by_id(fax_document.fax_account_id); if not fax_account then - log:error('fax account ' .. fax_document.fax_account_id .. ' not found'); + log:error('FAX_SEND - fax account ' .. fax_document.fax_account_id .. ' not found'); return end local destination_number = fax_class:destination_number(document_id); if not destination_number or tostring(destination_number) == '' then - log:error('destination number not found'); + log:error('FAX_SEND - destination number not found'); return end diff --git a/private_pub.ru b/private_pub.ru deleted file mode 100644 index 2db4acf..0000000 --- a/private_pub.ru +++ /dev/null @@ -1,8 +0,0 @@ -# Run with: rackup private_pub.ru -s thin -E production -require "bundler/setup" -require "yaml" -require "faye" -require "private_pub" - -PrivatePub.load_config(File.expand_path("../config/private_pub.yml", __FILE__), ENV["RAILS_ENV"] || "development") -run PrivatePub.faye_app diff --git a/test/functional/backup_jobs_controller_test.rb b/test/functional/backup_jobs_controller_test.rb new file mode 100644 index 0000000..17a0caf --- /dev/null +++ b/test/functional/backup_jobs_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class BackupJobsControllerTest < ActionController::TestCase + setup do + @backup_job = backup_jobs(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:backup_jobs) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create backup_job" do + assert_difference('BackupJob.count') do + post :create, backup_job: @backup_job.attributes + end + + assert_redirected_to backup_job_path(assigns(:backup_job)) + end + + test "should show backup_job" do + get :show, id: @backup_job.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @backup_job.to_param + assert_response :success + end + + test "should update backup_job" do + put :update, id: @backup_job.to_param, backup_job: @backup_job.attributes + assert_redirected_to backup_job_path(assigns(:backup_job)) + end + + test "should destroy backup_job" do + assert_difference('BackupJob.count', -1) do + delete :destroy, id: @backup_job.to_param + end + + assert_redirected_to backup_jobs_path + end +end diff --git a/test/functional/intruders_controller_test.rb b/test/functional/intruders_controller_test.rb new file mode 100644 index 0000000..0896022 --- /dev/null +++ b/test/functional/intruders_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class IntrudersControllerTest < ActionController::TestCase + setup do + @intruder = intruders(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:intruders) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create intruder" do + assert_difference('Intruder.count') do + post :create, intruder: @intruder.attributes + end + + assert_redirected_to intruder_path(assigns(:intruder)) + end + + test "should show intruder" do + get :show, id: @intruder.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @intruder.to_param + assert_response :success + end + + test "should update intruder" do + put :update, id: @intruder.to_param, intruder: @intruder.attributes + assert_redirected_to intruder_path(assigns(:intruder)) + end + + test "should destroy intruder" do + assert_difference('Intruder.count', -1) do + delete :destroy, id: @intruder.to_param + end + + assert_redirected_to intruders_path + end +end diff --git a/test/functional/system_messages_controller_test.rb b/test/functional/system_messages_controller_test.rb deleted file mode 100644 index 2894cd3..0000000 --- a/test/functional/system_messages_controller_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'test_helper' - -class SystemMessagesControllerTest < ActionController::TestCase - setup do - @system_message = system_messages(:one) - end - - test "should get index" do - get :index - assert_response :success - assert_not_nil assigns(:system_messages) - end - - test "should get new" do - get :new - assert_response :success - end - - test "should create system_message" do - assert_difference('SystemMessage.count') do - post :create, system_message: @system_message.attributes - end - - assert_redirected_to system_message_path(assigns(:system_message)) - end - - test "should show system_message" do - get :show, id: @system_message.to_param - assert_response :success - end - - test "should get edit" do - get :edit, id: @system_message.to_param - assert_response :success - end - - test "should update system_message" do - put :update, id: @system_message.to_param, system_message: @system_message.attributes - assert_redirected_to system_message_path(assigns(:system_message)) - end - - test "should destroy system_message" do - assert_difference('SystemMessage.count', -1) do - delete :destroy, id: @system_message.to_param - end - - assert_redirected_to system_messages_path - end -end diff --git a/test/unit/backup_job_test.rb b/test/unit/backup_job_test.rb new file mode 100644 index 0000000..a63c219 --- /dev/null +++ b/test/unit/backup_job_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class BackupJobTest < ActiveSupport::TestCase + def test_should_be_valid + assert BackupJob.new.valid? + end +end diff --git a/test/unit/callthrough_test.rb b/test/unit/callthrough_test.rb index 5764c0d..2e8cc56 100644 --- a/test/unit/callthrough_test.rb +++ b/test/unit/callthrough_test.rb @@ -12,7 +12,7 @@ class CallthroughTest < ActiveSupport::TestCase @gemeinschaft_setup.country = Country.first @gemeinschaft_setup.language = Language.first - @current_user = @gemeinschaft_setup.build_user( + current_user = @gemeinschaft_setup.build_user( :user_name => I18n.t('gemeinschaft_setups.initial_setup.admin_name'), :male => true, :email => 'admin@localhost', @@ -52,18 +52,18 @@ class CallthroughTest < ActiveSupport::TestCase @tenant.did_list = '02622-70648-x, 02622-706480' @tenant.save - @tenant.tenant_memberships.create(:user_id => @current_user.id) - @current_user.update_attributes!(:current_tenant_id => @tenant.id) + @tenant.tenant_memberships.create(:user_id => current_user.id) + current_user.update_attributes!(:current_tenant_id => @tenant.id) # The first user becomes a member of the 'admin' UserGroup # admin_group = @tenant.user_groups.create(:name => I18n.t('gemeinschaft_setups.initial_setup.admin_group_name')) - admin_group.users << @current_user + admin_group.users << current_user # User group # user_group = @tenant.user_groups.create(:name => I18n.t('gemeinschaft_setups.initial_setup.user_group_name')) - user_group.users << @current_user + user_group.users << current_user # Generate the internal_extensions # @@ -84,7 +84,7 @@ class CallthroughTest < ActiveSupport::TestCase # assert @gemeinschaft_setup.valid? assert @sip_domain.valid? - assert @current_user.valid? + assert current_user.valid? assert @tenant.valid? diff --git a/test/unit/intruder_test.rb b/test/unit/intruder_test.rb new file mode 100644 index 0000000..f1b7963 --- /dev/null +++ b/test/unit/intruder_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class IntruderTest < ActiveSupport::TestCase + def test_should_be_valid + assert Intruder.new.valid? + end +end diff --git a/test/unit/system_message_test.rb b/test/unit/system_message_test.rb deleted file mode 100644 index 0476ac8..0000000 --- a/test/unit/system_message_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test_helper' - -class SystemMessageTest < ActiveSupport::TestCase - # def test_should_be_valid - # assert SystemMessage.new.valid? - # end -end |