diff options
157 files changed, 2553 insertions, 556 deletions
diff --git a/app/assets/javascripts/forms.js.coffee b/app/assets/javascripts/forms.js.coffee new file mode 100644 index 0000000..42b1c45 --- /dev/null +++ b/app/assets/javascripts/forms.js.coffee @@ -0,0 +1,11 @@ +# Simple Form Toggle for required fields +$(document).ready -> + validate_fields = (obj)-> + if ($(obj).val() == "") + $(obj).addClass "invalid" + else + $(obj).removeClass "invalid" + + sel = "input.required, textarea.required" + $(sel).each (i, e)-> validate_fields(e) + $(sel).keyup -> validate_fields(this) diff --git a/app/assets/stylesheets/gemeinschaft-generic.css.scss b/app/assets/stylesheets/gemeinschaft-generic.css.scss index fbeaa1f..9448b84 100644 --- a/app/assets/stylesheets/gemeinschaft-generic.css.scss +++ b/app/assets/stylesheets/gemeinschaft-generic.css.scss @@ -25,6 +25,28 @@ li.display { } input, textarea, .uneditable-input { width: 500px; + @media (max-width: 979px) { + width: 200px; + } + @media (max-width: 480px) { + width: 96%; + } +} +input, textarea { + &.invalid { + box-shadow: inset -9px 0px 0px rgb(255, 219, 219), inset -14px 0px 0px rgb(255, 245, 245) !important; + } +} + +select { + width: 520px; + @media (max-width: 979px) { + width: 220px; + } + @media (max-width: 480px) { + width: 99.5%; + } + } @media (max-width: 979px) { diff --git a/app/controllers/call_forwards_controller.rb b/app/controllers/call_forwards_controller.rb index b1ced87..34fb77a 100644 --- a/app/controllers/call_forwards_controller.rb +++ b/app/controllers/call_forwards_controller.rb @@ -1,7 +1,9 @@ class CallForwardsController < ApplicationController - load_and_authorize_resource :phone_number - load_and_authorize_resource :call_forward, :through => [:phone_number] + load_resource :phone_number + load_resource :sip_account + load_and_authorize_resource :call_forward, :through => [:phone_number, :sip_account] + before_filter :set_and_authorize_parent before_filter :spread_breadcrumbs class CallForwardingDestination @@ -20,7 +22,7 @@ class CallForwardsController < ApplicationController end def new - @call_forward = @phone_number.call_forwards.build + @call_forward = @parent.call_forwards.build @call_forward.depth = GsParameter.get('DEFAULT_CALL_FORWARD_DEPTH') @call_forward.active = true @call_forwarding_destinations = call_forwarding_destination_types() @@ -33,7 +35,7 @@ class CallForwardsController < ApplicationController end end - if @phone_number.call_forwards.where( + if @parent.call_forwards.where( :call_forward_case_id => CallForwardCase.find_by_value('noanswer').id, :active => true ).count == 0 @@ -43,10 +45,11 @@ class CallForwardsController < ApplicationController end def create - @call_forward = @phone_number.call_forwards.build( params[:call_forward] ) + @call_forward = @parent.call_forwards.build( params[:call_forward] ) if @call_forward.save - redirect_to phone_number_call_forward_path( @phone_number, @call_forward ), :notice => t('call_forwards.controller.successfuly_created') + m = method( :"#{@parent.class.name.underscore}_call_forwards_url" ) + redirect_to m.( @parent ), :notice => t('call_forwards.controller.successfuly_created') else @available_call_forward_cases = CallForwardCase.all render :new @@ -61,7 +64,8 @@ class CallForwardsController < ApplicationController def update @available_call_forward_cases = CallForwardCase.all if @call_forward.update_attributes(params[:call_forward]) - redirect_to phone_number_call_forward_path( @phone_number, @call_forward ), :notice => t('call_forwards.controller.successfuly_updated') + m = method( :"#{@parent.class.name.underscore}_call_forwards_url" ) + redirect_to m.( @parent ), :notice => t('call_forwards.controller.successfuly_updated') else @call_forwarding_destinations = call_forwarding_destination_types() render :edit @@ -70,30 +74,48 @@ class CallForwardsController < ApplicationController def destroy @call_forward.destroy - redirect_to phone_number_call_forwards_path( @phone_number ), :notice => t('call_forwards.controller.successfuly_destroyed') + m = method( :"#{@parent.class.name.underscore}_call_forwards_url" ) + redirect_to m.( @parent ), :notice => t('call_forwards.controller.successfuly_destroyed') end private + private + def set_and_authorize_parent + @parent = @sip_account || @phone_number + authorize! :read, @parent + end + def spread_breadcrumbs - if @phone_number && @phone_number.phone_numberable_type == 'SipAccount' - @sip_account = @phone_number.phone_numberable + if @parent + if @parent.class == PhoneNumber && @parent.phone_numberable_type == 'SipAccount' + @sip_account = @parent.phone_numberable + end if @sip_account.sip_accountable_type == 'User' - @user = @phone_number.phone_numberable.sip_accountable - add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) - add_breadcrumb @user, tenant_users_path(@user.current_tenant, @user) - add_breadcrumb t("sip_accounts.index.page_title"), user_sip_accounts_path(@user) - add_breadcrumb @sip_account, user_sip_account_path(@user, @sip_account) + @user = @sip_account.sip_accountable + if @parent.class == PhoneNumber + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_users_path(@user.current_tenant, @user) + add_breadcrumb t("sip_accounts.index.page_title"), user_sip_accounts_path(@user) + add_breadcrumb @sip_account, user_sip_account_path(@user, @sip_account) + add_breadcrumb t("phone_numbers.index.page_title"), sip_account_phone_numbers_path(@sip_account) + add_breadcrumb @parent, sip_account_phone_number_path(@sip_account, @parent) + elsif @parent.class == SipAccount + add_breadcrumb t("users.index.page_title"), tenant_users_path(@user.current_tenant) + add_breadcrumb @user, tenant_users_path(@user.current_tenant, @user) + add_breadcrumb t("sip_accounts.index.page_title"), user_sip_accounts_path(@user) + end end if @sip_account.sip_accountable_type == 'Tenant' @tenant = @sip_account.sip_accountable add_breadcrumb t("sip_accounts.index.page_title"), tenant_sip_accounts_path(@tenant) add_breadcrumb @sip_account, tenant_sip_account_path(@tenant, @sip_account) end - add_breadcrumb t("phone_numbers.index.page_title"), sip_account_phone_numbers_path(@sip_account) - add_breadcrumb @phone_number, sip_account_phone_number_path(@sip_account, @phone_number) - add_breadcrumb t("call_forwards.index.page_title"), phone_number_call_forwards_path(@phone_number) + + m = method( :"#{@parent.class.name.underscore}_call_forwards_url" ) + add_breadcrumb t("call_forwards.index.page_title"), m.(@parent) if @call_forward && !@call_forward.new_record? - add_breadcrumb @call_forward, phone_number_call_forward_path(@phone_number, @call_forward) + m = method( :"#{@parent.class.name.underscore}_call_forward_path" ) + add_breadcrumb @call_forward, m.(@parent, @call_forward) end end end diff --git a/app/controllers/calls_controller.rb b/app/controllers/calls_controller.rb index d5f3b42..5534b1b 100644 --- a/app/controllers/calls_controller.rb +++ b/app/controllers/calls_controller.rb @@ -1,6 +1,58 @@ class CallsController < ApplicationController + load_resource :sip_account + load_resource :call + before_filter :set_and_authorize_parent + def index - @calls = Call.all + if @parent + @calls = @parent.calls + else + @calls = Call.all + end + end + + def new + if !params[:url].blank? + protocol, separator, phone_number = params[:url].partition(':') + if ! phone_number.blank? + @call = @parent.calls.new() + @call.dest = phone_number + end + elsif !params[:number].blank? + @call = @parent.calls.new() + @call.dest = params[:number] + end + end + + def show + redirect_to :index + end + + def create + params[:call][:sip_account] = @sip_account + @call = Call.create(params[:call]) + + if @call && @call.call + m = method( :"#{@parent.class.name.underscore}_calls_url" ) + redirect_to m.( @parent ), :notice => t('calls.controller.successfuly_created') + else + render :new + end + end + + def destroy + @call.destroy + if @parent + m = method( :"#{@parent.class.name.underscore}_calls_url" ) + else + m = method( :"calls_url" ) + end + redirect_to m.(@parent), :notice => t('calls.controller.successfuly_destroyed') + end + + private + def set_and_authorize_parent + @parent = @sip_account end end diff --git a/app/controllers/config_siemens_controller.rb b/app/controllers/config_siemens_controller.rb index bbeba46..1966d49 100644 --- a/app/controllers/config_siemens_controller.rb +++ b/app/controllers/config_siemens_controller.rb @@ -1068,8 +1068,8 @@ class ConfigSiemensController < ApplicationController phone_numbers.push(phone_number.number) assistant_call_forwardings = phone_number.call_forwards.where(:call_forward_case_id => CallForwardCase.where(:value => 'assistant').first.id) assistant_call_forwardings.each do |assistant_call_forwarding| - if assistant_call_forwarding.call_forwardable_type == 'HuntGroup' && assistant_call_forwarding.call_forwardable_id.to_i > 0 - hunt_groups.push(assistant_call_forwarding.call_forwardable_id.to_i) + if assistant_call_forwarding.destinationable_type == 'HuntGroup' && assistant_call_forwarding.destinationable_id.to_i > 0 + hunt_groups.push(assistant_call_forwarding.destinationable_id.to_i) end end end diff --git a/app/controllers/config_snom_controller.rb b/app/controllers/config_snom_controller.rb index 76fa633..eb94038 100644 --- a/app/controllers/config_snom_controller.rb +++ b/app/controllers/config_snom_controller.rb @@ -799,7 +799,7 @@ AAAA' end phone_book_entry.phone_numbers.each do |phone_number| if phone_book_entry.phone_numbers.count > 1 - entry_name = " #{phone_number.name} #{phone_number.number}" + entry_name = "- #{phone_number.name} #{phone_number.number}" else entry_name = "#{phone_book_entry.to_s} #{phone_number.number}" end diff --git a/app/controllers/fax_documents_controller.rb b/app/controllers/fax_documents_controller.rb index 5653683..c2b3083 100644 --- a/app/controllers/fax_documents_controller.rb +++ b/app/controllers/fax_documents_controller.rb @@ -31,6 +31,24 @@ class FaxDocumentsController < ApplicationController ) end } + format.tiff { + caller_number = @fax_document.caller_id_number.to_s.gsub(/[^0-9]/, '') + if caller_number.blank? + caller_number = 'anonymous' + end + + if @fax_document.tiff + send_file @fax_document.tiff, :type => "image/tiff", + :filename => "#{@fax_document.created_at.strftime('%Y%m%d-%H%M%S')}-#{caller_number}.tiff" + else + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "<!-- Raw image not found -->", + ) + end + } end end diff --git a/app/controllers/group_memberships_controller.rb b/app/controllers/group_memberships_controller.rb new file mode 100644 index 0000000..e0f897b --- /dev/null +++ b/app/controllers/group_memberships_controller.rb @@ -0,0 +1,53 @@ +class GroupMembershipsController < ApplicationController + load_and_authorize_resource :group + load_and_authorize_resource :group_membership, :through => [:group] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + end + + def create + if params[:group_membership][:item_type].blank? + params[:group_membership][:item_type] = @group.group_memberships.first.item_type + end + @group_membership = @group.group_memberships.new(params[:group_membership]) + if @group_membership.save + redirect_to action: "index", :notice => t('group_memberships.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @group_membership.update_attributes(params[:group_membership]) + redirect_to action: "index", :notice => t('group_memberships.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @group_membership.destroy + redirect_to action: "index", :notice => t('group_memberships.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + add_breadcrumb t("groups.index.page_title"), groups_path + add_breadcrumb @group, group_path(@group) + add_breadcrumb t("group_memberships.index.page_title"), group_group_memberships_path(@group) + if @group_membership && !@group_membership.new_record? + add_breadcrumb @group_membership, group_group_membership_path(@group, @group_membership) + end + end +end diff --git a/app/controllers/group_permissions_controller.rb b/app/controllers/group_permissions_controller.rb new file mode 100644 index 0000000..b6517b1 --- /dev/null +++ b/app/controllers/group_permissions_controller.rb @@ -0,0 +1,51 @@ +class GroupPermissionsController < ApplicationController + load_and_authorize_resource :group + load_and_authorize_resource :group_permission, :through => [:group] + + before_filter :spread_breadcrumbs + + def index + end + + def show + end + + def new + @group_permission.target_group_id = @group_permission.group_id + end + + def create + @group_permission = @group.group_permissions.new(params[:group_permission]) + if @group_permission.save + redirect_to action: "index", :notice => t('group_permissions.controller.successfuly_created') + else + render :new + end + end + + def edit + end + + def update + if @group_permission.update_attributes(params[:group_permission]) + redirect_to action: "index", :notice => t('group_permissions.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @group_permission.destroy + redirect_to action: "index", :notice => t('group_permissions.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + add_breadcrumb t("groups.index.page_title"), groups_path + add_breadcrumb @group, group_path(@group) + add_breadcrumb t("group_permissions.index.page_title"), group_group_permissions_path(@group) + if @group_permission && !@group_permission.new_record? + add_breadcrumb @group_permission, group_group_permission_path(@group, @group_permission) + end + end +end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb new file mode 100644 index 0000000..74ad7c8 --- /dev/null +++ b/app/controllers/groups_controller.rb @@ -0,0 +1,52 @@ +class GroupsController < ApplicationController + load_and_authorize_resource :group + before_filter :spread_breadcrumbs + + def index + @groups = Group.all + end + + def show + @group = Group.find(params[:id]) + end + + def new + @group = Group.new + end + + def create + @group = Group.new(params[:group]) + if @group.save + redirect_to @group, :notice => t('groups.controller.successfuly_created') + else + render :new + end + end + + def edit + @group = Group.find(params[:id]) + end + + def update + @group = Group.find(params[:id]) + if @group.update_attributes(params[:group]) + redirect_to @group, :notice => t('groups.controller.successfuly_updated') + else + render :edit + end + end + + def destroy + @group = Group.find(params[:id]) + @group.destroy + redirect_to groups_url, :notice => t('groups.controller.successfuly_destroyed') + end + + private + def spread_breadcrumbs + add_breadcrumb t("groups.index.page_title"), groups_path + if @group && !@group.new_record? + add_breadcrumb @group, @group + end + end +end diff --git a/app/controllers/intruders_controller.rb b/app/controllers/intruders_controller.rb index 147e06d..d3c767e 100644 --- a/app/controllers/intruders_controller.rb +++ b/app/controllers/intruders_controller.rb @@ -1,6 +1,8 @@ class IntrudersController < ApplicationController + load_and_authorize_resource :intruder + def index - @intruders = Intruder.all + @intruders = Intruder.order('list_type ASC, contact_last DESC').all spread_breadcrumbs end diff --git a/app/controllers/page_controller.rb b/app/controllers/page_controller.rb index ed48e3c..10ecf2c 100644 --- a/app/controllers/page_controller.rb +++ b/app/controllers/page_controller.rb @@ -7,6 +7,8 @@ class PageController < ApplicationController def index if current_user redirect_to [current_user.current_tenant, current_user] + else + redirect_to log_in_path end end diff --git a/app/controllers/restore_jobs_controller.rb b/app/controllers/restore_jobs_controller.rb new file mode 100644 index 0000000..bfecc33 --- /dev/null +++ b/app/controllers/restore_jobs_controller.rb @@ -0,0 +1,25 @@ +class RestoreJobsController < ApplicationController + skip_before_filter :start_setup_if_new_installation, :only => [:new, :create, :show, :index] + + load_and_authorize_resource :restore_job + + def index + end + + def show + end + + def new + end + + def create + @restore_job.state = 'new' + + if @restore_job.save + session[:user_id] = nil + redirect_to @restore_job, :notice => t('restore_jobs.controller.successfuly_created') + else + render :new + end + end +end diff --git a/app/controllers/ringtones_controller.rb b/app/controllers/ringtones_controller.rb index 7ffe30e..e5a4f64 100644 --- a/app/controllers/ringtones_controller.rb +++ b/app/controllers/ringtones_controller.rb @@ -1,7 +1,8 @@ class RingtonesController < ApplicationController load_resource :phone_number + load_resource :sip_account load_resource :boss_assistant_cooperation - load_and_authorize_resource :ringtone, :through => [:phone_number, :boss_assistant_cooperation] + load_and_authorize_resource :ringtone, :through => [:phone_number, :sip_account, :boss_assistant_cooperation] before_filter :set_parent before_filter :spread_breadcrumbs @@ -14,12 +15,13 @@ class RingtonesController < ApplicationController def new @ringtone = @parent.ringtones.build + @ringtone.bellcore_id = GsParameter.get('default_ringtone', 'dialplan', 'parameters') end def create @ringtone = @parent.ringtones.build(params[:ringtone]) if @ringtone.save - redirect_to phone_number_ringtone_path(@parent, @ringtone), :notice => t('ringtones.controller.successfuly_created') + redirect_to method( :"#{@parent.class.name.underscore}_ringtones_url" ).(@parent), :notice => t('ringtones.controller.successfuly_created') else render :new end @@ -30,7 +32,7 @@ class RingtonesController < ApplicationController def update if @ringtone.update_attributes(params[:ringtone]) - redirect_to method( :"#{@parent.class.name.underscore}_ringtone_path" ).(@ringtone.ringtoneable, @ringtone), :notice => t('ringtones.controller.successfuly_updated') + redirect_to method( :"#{@parent.class.name.underscore}_ringtones_url" ).(@parent), :notice => t('ringtones.controller.successfuly_updated') else render :edit end @@ -38,12 +40,12 @@ class RingtonesController < ApplicationController def destroy @ringtone.destroy - redirect_to phone_number_ringtones_path(@parent), :notice => t('ringtones.controller.successfuly_destroyed') + redirect_to method( :"#{@parent.class.name.underscore}_ringtones_url" ).(@parent), :notice => t('ringtones.controller.successfuly_destroyed') end private def set_parent - @parent = @phone_number || @boss_assistant_cooperation + @parent = @phone_number || @boss_assistant_cooperation || @sip_account end def spread_breadcrumbs diff --git a/app/controllers/sip_accounts_controller.rb b/app/controllers/sip_accounts_controller.rb index b5c3ae4..621bd3c 100644 --- a/app/controllers/sip_accounts_controller.rb +++ b/app/controllers/sip_accounts_controller.rb @@ -1,6 +1,7 @@ class SipAccountsController < ApplicationController load_resource :user load_resource :tenant + load_and_authorize_resource :sip_account, :only => [:call] load_and_authorize_resource :sip_account, :through => [:user, :tenant ] before_filter :set_and_authorize_parent @@ -10,6 +11,7 @@ class SipAccountsController < ApplicationController end def show + @register_tel_protocol = "#{request.protocol}#{request.host_with_port}/sip_accounts/#{@sip_account.try(:id)}/call?url=%s" end def new @@ -74,6 +76,36 @@ class SipAccountsController < ApplicationController redirect_to :root, :notice => t('sip_accounts.controller.successfuly_destroyed') end + def call + if !params[:url].blank? + protocol, separator, phone_number = params[:url].partition(':') + if ! phone_number.blank? + @sip_account.call(phone_number) + render( + :status => 200, + :layout => false, + :content_type => 'text/plain', + :text => "<!-- CALL -->", + ) + return; + end + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "<!-- Number not found -->", + ) + return; + end + + render( + :status => 404, + :layout => false, + :content_type => 'text/plain', + :text => "<!-- Call URL not found -->", + ) + end + private def set_and_authorize_parent @parent = @user || @tenant diff --git a/app/controllers/trigger_controller.rb b/app/controllers/trigger_controller.rb index 2b491be..64a5f91 100644 --- a/app/controllers/trigger_controller.rb +++ b/app/controllers/trigger_controller.rb @@ -1,7 +1,4 @@ class TriggerController < ApplicationController - TIFF_FUFFIX = ".tiff" - PDF_SUFFIX = ".pdf" - TMP_DIR = "/tmp/" def voicemail if !params[:sip_account_id].blank? @@ -68,44 +65,29 @@ class TriggerController < ApplicationController if fax_account fax_account.fax_documents.where(:state => 'received').each do |fax_document| - tiff_file = File.basename(fax_document.tiff.to_s) + pdf_file = fax_document.tiff_to_pdf - if !File.exists?( "#{TMP_DIR}#{tiff_file}" ) + if !pdf_file fax_document.state = 'unsuccessful' fax_document.save next end - paper_size = "letter" - pdf_file = "#{TMP_DIR}#{File.basename(tiff_file, TIFF_FUFFIX)}#{PDF_SUFFIX}" - - system "tiff2pdf \\ - -o \"#{pdf_file}\" \\ - -p #{paper_size} \\ - -a \"#{fax_document.remote_station_id}\" \\ - -c \"AMOOMA Gemeinschaft version #{GsParameter.get('GEMEINSCHAFT_VERSION')}\" \\ - -t \"#{fax_document.remote_station_id}\" \"#{TMP_DIR}#{tiff_file}\"" - - if !File.exists?( pdf_file ) - fax_document.state = 'unsuccessful' - fax_document.save - next + working_path, tiff_file = File.split(fax_document.tiff) + if fax_document.store_dir != working_path + FileUtils.mkdir(fax_document.store_dir) + FileUtils.mv(fax_document.tiff, fax_document.store_dir) + fax_document.tiff = "#{fax_document.store_dir}/#{tiff_file}" end fax_document.document = File.open(pdf_file) fax_document.state = 'successful' if fax_document.save - Notifications.new_fax(fax_document).deliver - begin - File.delete("#{TMP_DIR}#{tiff_file}"); - rescue => e - logger.error "Raw fax file could not be deleted: #{TMP_DIR}#{tiff_file} => #{e.inspect}" - end begin - File.delete(pdf_file); + File.delete(pdf_file) rescue => e - logger.error "PDF fax file could not be deleted: #{TMP_DIR}#{pdf_file} => #{e.inspect}" + logger.error "PDF fax file could not be deleted: #{pdf_file} => #{e.inspect}" end fax_document.tiff = nil fax_document.save diff --git a/app/helpers/group_memberships_helper.rb b/app/helpers/group_memberships_helper.rb new file mode 100644 index 0000000..837bafd --- /dev/null +++ b/app/helpers/group_memberships_helper.rb @@ -0,0 +1,2 @@ +module GroupMembershipsHelper +end diff --git a/app/helpers/group_permissions_helper.rb b/app/helpers/group_permissions_helper.rb new file mode 100644 index 0000000..45571d0 --- /dev/null +++ b/app/helpers/group_permissions_helper.rb @@ -0,0 +1,2 @@ +module GroupPermissionsHelper +end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb new file mode 100644 index 0000000..c091b2f --- /dev/null +++ b/app/helpers/groups_helper.rb @@ -0,0 +1,2 @@ +module GroupsHelper +end diff --git a/app/helpers/restore_jobs_helper.rb b/app/helpers/restore_jobs_helper.rb new file mode 100644 index 0000000..9a5d120 --- /dev/null +++ b/app/helpers/restore_jobs_helper.rb @@ -0,0 +1,2 @@ +module RestoreJobsHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb index d66577d..3ba4481 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -90,6 +90,11 @@ class Ability # SIM cards # cannot [:edit, :update], SimCard + + # Restore is only possible on a new system. + # + cannot :manage, RestoreJob + else # Any user can do the following stuff. # @@ -126,11 +131,12 @@ class Ability # SipAccounts and Phones # - can :read, SipAccount, :sip_accountable_type => 'User', :sip_accountable_id => user.id + can [:read, :call], SipAccount, :sip_accountable_type => 'User', :sip_accountable_id => user.id user.sip_accounts.each do |sip_account| can :read, PhoneNumber, :id => sip_account.phone_number_ids - can :manage, CallForward, :phone_number_id => sip_account.phone_number_ids + can :manage, CallForward, :call_forwardable_id => sip_account.phone_number_ids can :manage, Ringtone, :ringtoneable_type => 'PhoneNumber', :ringtoneable_id => sip_account.phone_number_ids + can :manage, Ringtone, :ringtoneable_type => 'SipAccount', :ringtoneable_id => sip_account.id can [:read, :destroy, :call] , CallHistory, :id => sip_account.call_history_ids end can :read, Phone, :phoneable_type => 'User', :phoneable_id => user.id @@ -158,7 +164,7 @@ class Ability # User can manage CallForwards of the PhoneNumbers of his # own SipAccounts: # - can :manage, CallForward, :phone_number_id => user.phone_number_ids + can :manage, CallForward, :call_forwardable_id => user.phone_number_ids # SoftkeyFunctions # @@ -176,6 +182,7 @@ class Ability # can :create, GemeinschaftSetup can :manage, SipDomain + can [:create, :new, :show, :index], RestoreJob end end diff --git a/app/models/backup_job.rb b/app/models/backup_job.rb index 96574a7..a04f6c0 100644 --- a/app/models/backup_job.rb +++ b/app/models/backup_job.rb @@ -32,7 +32,7 @@ class BackupJob < ActiveRecord::Base 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)}" + system "cd #{backup_directory} && sudo /bin/tar czf #{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz #{File.basename(tmp_backup_directory)}" require 'fileutils' FileUtils.rm_rf tmp_backup_directory file = File::Stat.new("#{backup_directory}/#{backup_name_prefix}#{File.basename(tmp_backup_directory)}.tar.gz") diff --git a/app/models/call.rb b/app/models/call.rb index c0f0f08..db6d9d6 100644 --- a/app/models/call.rb +++ b/app/models/call.rb @@ -1,9 +1,31 @@ class Call < ActiveRecord::Base self.table_name = 'detailed_calls' self.primary_key = 'uuid' + + attr_writer :sip_account_id + + validates :dest, + :presence => true - def readonly? - return true + def create(attributes=nil) + if ! attributes + return + end + + self.sip_account = SipAccount.where(:id => attributes[:sip_account_id]).first + self.dest = attributes[:dest] + return self + end + + def save(attributes=nil) + + end + + def call(number=nil) + if @sip_account && self.dest + return @sip_account.call(self.dest) + end + return false end def destroy @@ -15,15 +37,25 @@ class Call < ActiveRecord::Base return FreeswitchAPI.execute('uuid_kill', self.uuid, true); end + def sip_account=(sip_a) + @sip_account = sip_a + end + def sip_account + if @sip_account + return @sip_account + end + 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 + @sip_account = SipAccount.where(:auth_name => result[1], :sip_domain_id => domain.id).first end end + + return @sip_account end def sip_account_bleg @@ -69,4 +101,5 @@ class Call < ActiveRecord::Base true end end + end diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb index c668993..a932e11 100644 --- a/app/models/call_forward.rb +++ b/app/models/call_forward.rb @@ -6,17 +6,17 @@ class CallForward < ActiveRecord::Base :destination, :source, :depth, :active, :to_voicemail, :hunt_group_id, :call_forwardable_type, :call_forwardable_id, - :call_forwarding_destination, :position, :uuid + :call_forwarding_destination, :position, :uuid, + :destinationable_type, :destinationable_id - belongs_to :phone_number belongs_to :call_forwardable, :polymorphic => true - has_many :softkeys + belongs_to :destinationable, :polymorphic => true + has_many :softkeys, :as => :softkeyable - acts_as_list :scope => [ :phone_number_id, :call_forward_case_id ] + acts_as_list :scope => [ :call_forwardable_id, :call_forwardable_type, :call_forward_case_id ] - validates_presence_of :phone_number validates_presence_of :call_forward_case_id - validates_presence_of :destination, :if => Proc.new { |cf| cf.call_forwardable_type.to_s.downcase == 'phonenumber' || cf.call_forwardable_type.blank? } + validates_presence_of :destination, :if => Proc.new { |cf| cf.destinationable_type.to_s.downcase == 'phonenumber' || cf.destinationable_type.blank? } validates_inclusion_of :destination, :in => [ nil, '' ], @@ -24,8 +24,8 @@ class CallForward < ActiveRecord::Base belongs_to :call_forward_case - validates_presence_of :depth validates_numericality_of :depth, + :allow_nil => true, :only_integer => true, :greater_than_or_equal_to => 1, :less_than_or_equal_to => (GsParameter.get('MAX_CALL_FORWARD_DEPTH').nil? ? 0 : GsParameter.get('MAX_CALL_FORWARD_DEPTH')) @@ -44,25 +44,21 @@ class CallForward < ActiveRecord::Base :in => [ nil ], :if => Proc.new { |cf| cf.call_forward_case_id != 3 } - validate :validate_empty_hunt_group, :if => Proc.new { |cf| cf.active == true && cf.call_forwardable_type == 'HuntGroup' && cf.call_forward_case.value == 'assistant' } + validate :validate_empty_hunt_group, :if => Proc.new { |cf| cf.active == true && cf.destinationable_type == 'HuntGroup' && cf.call_forward_case.value == 'assistant' } validates_presence_of :uuid validates_uniqueness_of :uuid # Make sure the call forward's parent can't be changed: before_validation { |cfwd| - if cfwd.id \ - && cfwd.phone_number_id != cfwd.phone_number_id_was - errors.add( :phone_number_id, "cannot be changed." ) + if cfwd.id && (cfwd.call_forwardable_id != cfwd.call_forwardable_id_was || cfwd.call_forwardable_type != cfwd.call_forwardable_type_was) + errors.add( :call_forwardable_id, "cannot be changed." ) end } - #before_validation :set_call_forwardable before_save :split_and_format_destination_numbers after_save :set_presence - after_save :work_through_callforward_rules_act_per_sip_account after_save :deactivate_concurring_entries, :if => Proc.new { |cf| cf.active == true } - before_destroy :check_if_other_callforward_rules_have_to_be_destroyed before_destroy :deactivate_connected_softkeys def case_string @@ -70,70 +66,25 @@ class CallForward < ActiveRecord::Base end def to_s - if self.call_forwardable_type.blank? - self.call_forwardable_type = '' + if self.destinationable_type.blank? + self.destinationable_type = '' else - call_forwardable_type = " #{self.call_forwardable_type}" + destinationable_type = " #{self.destinationable_type}" end - if self.call_forwardable - destination = "#{self.call_forwardable}#{call_forwardable_type}" + if self.destinationable + destination = "#{self.destinationable}#{destinationable_type}" else - destination = "#{self.destination}#{call_forwardable_type}" + destination = "#{self.destination}#{destinationable_type}" end - "#{self.phone_number} (#{I18n.t("call_forward_cases.#{self.call_forward_case}")}) -> #{destination}" - end - - def set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account - # This is to make sure that no recursion kicks in. - # - if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account - return false - end - - old_value_of_callforward_rules_act_per_sip_account = self.phone_number.phone_numberable.callforward_rules_act_per_sip_account - self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => false}) - - attributes_of_this_call_forward = self.attributes.delete_if {|key, value| ['id','updated_at','created_at','phone_number_id','call_forward_case_id', 'uuid'].include?(key)} - phone_numbers = self.phone_number.phone_numberable.phone_numbers.where('id != ?', self.phone_number.id) - - phone_numbers.each do |phone_number| - # Problem - call_forward = phone_number.call_forwards.find_or_create_by_call_forward_case_id_and_position(self.call_forward_case_id, self.position, attributes_of_this_call_forward) - call_forward.update_attributes(attributes_of_this_call_forward) - end - - self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => old_value_of_callforward_rules_act_per_sip_account}) - end - - def destroy_all_similar_callforward_rules_of_the_parent_sip_account - # This is to make sure that no recursion kicks in. - # - if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account - return false - end - - old_value_of_callforward_rules_act_per_sip_account = self.phone_number.phone_numberable.callforward_rules_act_per_sip_account - self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => false}) - - phone_numbers_of_parent_sip_account = self.phone_number.phone_numberable.phone_numbers.where('id != ?', self.phone_number.id) - - phone_numbers_of_parent_sip_account.each do |phone_number| - if self.call_forwardable_type != 'Voicemail' - phone_number.call_forwards.where(:call_forward_case_id => self.call_forward_case_id, :destination => self.destination).destroy_all - else - phone_number.call_forwards.where(:call_forward_case_id => self.call_forward_case_id, :call_forwardable_type => self.call_forwardable_type).destroy_all - end - end - - self.phone_number.phone_numberable.update_attributes({:callforward_rules_act_per_sip_account => old_value_of_callforward_rules_act_per_sip_account}) + "#{self.call_forwardable} (#{I18n.t("call_forward_cases.#{self.call_forward_case}")}) -> #{destination}" end def call_forwarding_destination - "#{self.call_forwardable_id}:#{self.call_forwardable_type}" + "#{self.destinationable_id}:#{self.destinationable_type}" end def call_forwarding_destination=(destination_record) - self.call_forwardable_id, delimeter, self.call_forwardable_type = destination_record.to_s.partition(':') + self.destinationable_id, delimeter, self.destinationable_type = destination_record.to_s.partition(':') end def toggle @@ -168,7 +119,7 @@ class CallForward < ActiveRecord::Base state = 'terminated' if self.active - if self.call_forwardable_type and self.call_forwardable_type.downcase() == 'voicemail' + if self.destinationable_type and self.destinationable_type.downcase() == 'voicemail' state = 'early' else state = 'confirmed' @@ -187,47 +138,28 @@ class CallForward < ActiveRecord::Base #return send_presence_event(self.call_forward_case.value, state) end - def set_call_forwardable + def set_destinationable if @hunt_group_id && HuntGroup.where(:id => @hunt_group_id.to_i).count > 0 - self.call_forwardable = HuntGroup.where(:id => @hunt_group_id.to_i).first + self.destinationable = HuntGroup.where(:id => @hunt_group_id.to_i).first end if @to_voicemail && @to_voicemail.first.downcase == 'true' - self.call_forwardable_type = 'Voicemail' - self.call_forwardable_id = nil + self.destinationable_type = 'Voicemail' + self.destinationable_id = nil end end - def work_through_callforward_rules_act_per_sip_account - if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account - return false - end - - if self.phone_number.phone_numberable.callforward_rules_act_per_sip_account == true - self.set_this_callforward_rule_to_all_phone_numbers_of_the_parent_sip_account - end - end - - def check_if_other_callforward_rules_have_to_be_destroyed - if ! self.phone_number.phone_numberable.respond_to? :callforward_rules_act_per_sip_account - return false - end - - if self.phone_number.phone_numberable.callforward_rules_act_per_sip_account == true - self.destroy_all_similar_callforward_rules_of_the_parent_sip_account - end - end def send_presence_event(state, call_forwarding_service = nil) dialplan_function = "cftg-#{self.id}" unique_id = "call_forwarding_#{self.id}" if call_forwarding_service == 'always' - dialplan_function = "cfutg-#{self.phone_number.id}" - unique_id = "call_forwarding_number_#{self.phone_number.id}" + dialplan_function = "cfutg-#{self.call_forwardable.id}" + unique_id = "call_forwarding_number_#{self.call_forwardable.id}" elsif call_forwarding_service == 'assistant' - dialplan_function = "cfatg-#{self.phone_number.id}" - unique_id = "call_forwarding_number_#{self.phone_number.id}" + dialplan_function = "cfatg-#{self.call_forwardable.id}" + unique_id = "call_forwarding_number_#{self.call_forwardable.id}" end if dialplan_function @@ -245,7 +177,7 @@ class CallForward < ActiveRecord::Base end def deactivate_concurring_entries - CallForward.where(:phone_number_id => self.phone_number_id, :call_forward_case_id => self.call_forward_case_id, :active => true).each do |call_forwarding_entry| + CallForward.where(:call_forwardable_id => self.call_forwardable_id, :call_forwardable_type => self.call_forwardable_type, :call_forward_case_id => self.call_forward_case_id, :active => true).each do |call_forwarding_entry| if call_forwarding_entry.id != self.id call_forwarding_entry.update_attributes(:active => false) end @@ -253,7 +185,7 @@ class CallForward < ActiveRecord::Base end def validate_empty_hunt_group - hunt_group = self.call_forwardable + hunt_group = self.destinationable if hunt_group && hunt_group.hunt_group_members.where(:active => true).count == 0 errors.add(:call_forwarding_destination, 'HuntGroup has no active members') end diff --git a/app/models/fax_document.rb b/app/models/fax_document.rb index 564d3bb..5b27965 100644 --- a/app/models/fax_document.rb +++ b/app/models/fax_document.rb @@ -1,8 +1,7 @@ class FaxDocument < ActiveRecord::Base # attr_accessible :inbound, :transmission_time, :sent_at, :document_total_pages, :document_transferred_pages, :ecm_requested, :ecm_used, :image_resolution, :image_size, :local_station_id, :result_code, :result_text, :remote_station_id, :success, :transfer_rate, :t38_gateway_format, :t38_peer, :document - mount_uploader :document, DocumentUploader - mount_uploader :tiff, TiffUploader + mount_uploader :document, FaxDocumentUploader validates_presence_of :document validates_numericality_of :retry_counter, :only_integer => true, :greater_than_or_equal_to => 0 @@ -18,8 +17,10 @@ class FaxDocument < ActiveRecord::Base has_many :fax_thumbnails, :order => :position, :dependent => :destroy - after_create :convert_pdf_to_tiff + after_save :convert_to_tiff after_create :render_thumbnails + + after_destroy :remove_storage_dir # Scopes scope :inbound, where(:state => 'inbound') @@ -57,7 +58,7 @@ class FaxDocument < ActiveRecord::Base end def create_thumbnails_and_save_them - tmp_dir = "/tmp/fax_convertions/#{self.id}" + tmp_dir = "/var/spool/gemeinschaft/fax_convertions/#{self.id}" FileUtils.mkdir_p tmp_dir system("cd #{tmp_dir} && convert #{self.document.path} -colorspace Gray PNG:'fax_page.png'") Dir.glob("#{tmp_dir}/fax_page*.png").each do |thumbnail| @@ -68,17 +69,64 @@ class FaxDocument < ActiveRecord::Base FileUtils.rm_rf tmp_dir end - private - def convert_pdf_to_tiff + def tiff_to_pdf + if !File.exists?(self.tiff) + return nil + end + + working_path, file_name = File.split(self.tiff) + pdf_file = "#{working_path}/#{File.basename(self.tiff, '.tiff')}.pdf" + + system "tiff2pdf \\ + -o \"#{pdf_file}\" \\ + -p letter \\ + -a \"#{self.remote_station_id}\" \\ + -c \"AMOOMA Gemeinschaft version #{GsParameter.get('GEMEINSCHAFT_VERSION')}\" \\ + -t \"#{self.remote_station_id}\" \"#{self.tiff}\"" + + if !File.exists?(pdf_file) + return nil + end + + return pdf_file + end + + def to_tiff page_size_a4 = '595 842' page_size_command = "<< /Policies << /PageSize 3 >> /InputAttributes currentpagedevice /InputAttributes get dup { pop 1 index exch undef } forall dup 0 << /PageSize [ #{page_size_a4} ] >> put >> setpagedevice" - directory = "/tmp/GS-#{GsParameter.get('GEMEINSCHAFT_VERSION')}/faxes/#{self.id}" - FileUtils.mkdir_p directory - tiff_file_name = File.basename(self.document.to_s.downcase, ".pdf") + '.tiff' - system "cd #{directory} && gs -q -r#{self.fax_resolution.resolution_value} -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=\"#{tiff_file_name}\" -c \"#{page_size_command}\" -- \"#{Rails.root.to_s}/public#{self.document.to_s}\"" - self.tiff = File.open("#{directory}/#{tiff_file_name}") - self.save - FileUtils.rm_rf directory + working_path, file_name = File.split(self.document.to_s) + tiff_file = File.basename(file_name.to_s.downcase, File.extname(file_name)) + '.tiff' + result = system "cd #{store_dir} && gs -q -r#{self.fax_resolution.resolution_value} -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=\"#{tiff_file}\" -c \"#{page_size_command}\" -- \"#{self.document.to_s}\"" + + if !File.exists?("#{store_dir}/#{tiff_file}") + return nil + end + + return "#{store_dir}/#{tiff_file}" + end + + def store_dir + if self.try(:inbound) + "/var/opt/gemeinschaft/fax/in/#{self.id.to_i}" + else + "/var/opt/gemeinschaft/fax/out/#{self.id.to_i}" + end + end + + private + def convert_to_tiff + if self.tiff.blank? + self.tiff = self.to_tiff + if self.tiff + return self.save + end + end + end + + def remove_storage_dir + if File.directory?(self.store_dir) + FileUtils.rm_rf(self.store_dir) + end end end diff --git a/app/models/group.rb b/app/models/group.rb new file mode 100644 index 0000000..e0cfaab --- /dev/null +++ b/app/models/group.rb @@ -0,0 +1,11 @@ +class Group < ActiveRecord::Base + attr_accessible :name, :active, :comment + + has_many :group_memberships, :dependent => :destroy + has_many :group_permissions, :dependent => :destroy + has_many :permittances, :foreign_key => :target_group_id, :class_name => "GroupPermission", :dependent => :destroy + + def to_s + self.name + end +end diff --git a/app/models/group_membership.rb b/app/models/group_membership.rb new file mode 100644 index 0000000..0f04ae1 --- /dev/null +++ b/app/models/group_membership.rb @@ -0,0 +1,37 @@ +class GroupMembership < ActiveRecord::Base + attr_accessible :group_id, :item_type, :item_id + + belongs_to :group + belongs_to :item, :polymorphic => true + + validates :item_id, + :presence => true, + :uniqueness => { :scope => [:group_id, :item_type] } + + validates :item_type, + :presence => true, + :uniqueness => { :scope => [:group_id, :item_id] } + + validate :validate_item_type_consitency + + validates :item, + :presence => true + + def to_s + "#{self.item_type}: #{self.item}" + end + + def item_type_allowed + fist_item = self.group.group_memberships.first.try(:item) + if fist_item + return fist_item.class.name + end + end + + def validate_item_type_consitency + type_allowed = self.item_type_allowed + if type_allowed && type_allowed != self.item_type + errors.add(:item_type, "must be of type: #{type_allowed}") + end + end +end diff --git a/app/models/group_permission.rb b/app/models/group_permission.rb new file mode 100644 index 0000000..fe988ba --- /dev/null +++ b/app/models/group_permission.rb @@ -0,0 +1,24 @@ +class GroupPermission < ActiveRecord::Base + attr_accessible :group_id, :permission, :target_group_id + + PERMISSION_TYPES = ['pickup'] + + belongs_to :group + belongs_to :target_group, :class_name => "Group" + + validates :target_group_id, + :presence => true, + :uniqueness => { :scope => [:group_id, :permission] } + + validates :target_group, + :presence => true + + validates :permission, + :presence => true, + :uniqueness => { :scope => [:group_id, :target_group_id] }, + :inclusion => { :in => PERMISSION_TYPES } + + def to_s + "#{self.permission} => #{self.target_group}" + end +end diff --git a/app/models/gs_parameter.rb b/app/models/gs_parameter.rb index fe2a845..cd4f47b 100644 --- a/app/models/gs_parameter.rb +++ b/app/models/gs_parameter.rb @@ -10,9 +10,13 @@ class GsParameter < ActiveRecord::Base :presence => true, :inclusion => { :in => ['String', 'Integer', 'Boolean', 'YAML', 'Nil'] } - def self.get(wanted_variable) + def self.get(wanted_variable, entity=nil, section=nil) if GsParameter.table_exists? - item = GsParameter.where(:name => wanted_variable).first + if entity || section + item = GsParameter.where(:name => wanted_variable, :entity => entity, :section => section).first + else + item = GsParameter.where(:name => wanted_variable).first + end if item.nil? || item.class_type == 'Nil' return nil else diff --git a/app/models/hunt_group.rb b/app/models/hunt_group.rb index 5011bf0..7338606 100644 --- a/app/models/hunt_group.rb +++ b/app/models/hunt_group.rb @@ -2,7 +2,7 @@ class HuntGroup < ActiveRecord::Base attr_accessible :name, :strategy, :seconds_between_jumps, :phone_numbers_attributes belongs_to :tenant, :touch => true - has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy + has_many :call_forwards, :as => :destinationable, :dependent => :destroy validates_uniqueness_of :name, :scope => :tenant_id, :allow_nil => true, :allow_blank => true diff --git a/app/models/intruder.rb b/app/models/intruder.rb index 249fffc..97e3773 100644 --- a/app/models/intruder.rb +++ b/app/models/intruder.rb @@ -31,6 +31,41 @@ class Intruder < ActiveRecord::Base end end + def self.write_firewall_blacklist + firewall_blacklist_file = GsParameter.get('blacklist_file', 'perimeter', 'general') + entry_template = GsParameter.get('blacklist_file_entry', 'perimeter', 'general') + comment_template = GsParameter.get('blacklist_file_comment', 'perimeter', 'general') + File.open(firewall_blacklist_file, 'w') do |file| + Intruder.where(:list_type => 'blacklist').where('bans > 0').all.each do |entry| + if ! comment_template.blank? + file.write(self.expand_variables(comment_template, entry.to_hash) + "\n") + end + file.write(self.expand_variables(entry_template, entry.to_hash) + "\n") + end + end + end + + def self.expand_variables(line, variables) + return line.gsub(/\{([a-z_]+)\}/) do |m| + variables[$1.to_sym] + end + end + + def to_hash + return { + :key => self.key, + :points => self.points, + :bans => self.bans, + :received_port => self.contact_port, + :received_ip => self.contact_ip, + :contact_count => self.contact_count, + :user_agent => self.user_agent, + :to_user => self.to_user, + :comment => self.comment, + :date => DateTime.now.strftime('%Y-%m-%d %X') + } + end + private def set_key_if_empty if self.key.blank? diff --git a/app/models/phone_book_entry.rb b/app/models/phone_book_entry.rb index 275c7b6..96c8468 100644 --- a/app/models/phone_book_entry.rb +++ b/app/models/phone_book_entry.rb @@ -1,6 +1,8 @@ # encoding: UTF-8 class PhoneBookEntry < ActiveRecord::Base + PHONE_NUMBER_NAMES = ['Phone', 'Office', 'Home', 'Mobile', 'Fax'] + before_save :run_phonetic_algorithm before_save :save_value_of_to_s diff --git a/app/models/phone_number.rb b/app/models/phone_number.rb index d1e950f..f6453ce 100644 --- a/app/models/phone_number.rb +++ b/app/models/phone_number.rb @@ -3,7 +3,7 @@ class PhoneNumber < ActiveRecord::Base attr_accessible :name, :number, :gs_node_id, :access_authorization_user_id - has_many :call_forwards, :dependent => :destroy + has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy has_many :ringtones, :as => :ringtoneable, :dependent => :destroy diff --git a/app/models/restore_job.rb b/app/models/restore_job.rb new file mode 100644 index 0000000..80741ac --- /dev/null +++ b/app/models/restore_job.rb @@ -0,0 +1,24 @@ +class RestoreJob < ActiveRecord::Base + attr_accessible :state, :backup_file + + mount_uploader :backup_file, BackupFileUploader + + after_create :queue_the_restore_rake_task + + def to_s + if self.backup_file? + File.basename(self.backup_file.to_s) + else + "RestoreJob ID #{self.id}" + end + end + + private + def queue_the_restore_rake_task + self.delay.run_the_restore_rake_task + end + + def run_the_restore_rake_task + system "cd #{Rails.root} && rake backup:restore" + end +end diff --git a/app/models/ringtone.rb b/app/models/ringtone.rb index 36053c0..45ecd93 100644 --- a/app/models/ringtone.rb +++ b/app/models/ringtone.rb @@ -1,11 +1,25 @@ class Ringtone < ActiveRecord::Base attr_accessible :audio, :bellcore_id + CORE_RINGTONES_AVAILABLE = { + 'Silence' => 0, + 'Ringtone 1' => 1, + 'Ringtone 2' => 2, + 'Ringtone 3' => 3, + 'Ringtone 4' => 4, + 'Ringtone 5' => 5, + 'Ringtone 6' => 6, + 'Ringtone 7' => 7, + 'Ringtone 8' => 8, + 'Ringtone 9' => 9, + 'Ringtone 10' => 10, + } mount_uploader :audio, AudioUploader validates_presence_of :audio, :if => Proc.new{ |ringtone| ringtone.bellcore_id.blank? } validates_presence_of :ringtoneable_type validates_presence_of :ringtoneable_id validates_presence_of :ringtoneable + validates_uniqueness_of :ringtoneable_id, :scope => [:ringtoneable_type] belongs_to :ringtoneable, :polymorphic => true diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb index 7df8e3b..2040b41 100644 --- a/app/models/sip_account.rb +++ b/app/models/sip_account.rb @@ -16,7 +16,7 @@ class SipAccount < ActiveRecord::Base has_many :phones, :through => :phone_sip_accounts has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy - has_many :call_forwards, :through => :phone_numbers + has_many :call_forwards, :as => :call_forwardable, :dependent => :destroy belongs_to :tenant belongs_to :sip_domain @@ -33,6 +33,13 @@ class SipAccount < ActiveRecord::Base belongs_to :language, :foreign_key => 'language_code', :primary_key => 'code' + has_many :group_memberships, :as => :item, :dependent => :destroy, :uniq => true + has_many :groups, :through => :group_memberships + + has_many :ringtones, :as => :ringtoneable, :dependent => :destroy + + has_many :calls, :finder_sql => lambda { |s| "SELECT DISTINCT detailed_calls.* FROM detailed_calls WHERE presence_id LIKE '#{self.auth_name}@%'" } + # Delegations: # delegate :host, :to => :sip_domain, :allow_nil => true @@ -67,6 +74,7 @@ class SipAccount < ActiveRecord::Base validates_uniqueness_of :uuid after_create { self.create_on_other_gs_nodes('sip_accountable', self.sip_accountable.try(:uuid)) } + after_create :create_default_group_memberships after_destroy :destroy_on_other_gs_nodes after_update { self.update_on_other_gs_nodes('sip_accountable', self.sip_accountable.try(:uuid)) } @@ -92,8 +100,8 @@ class SipAccount < ActiveRecord::Base if call_forwarding_master.active call_forwarding_master.active = false else - if call_forwarding_service = 'assistant' && call_forwarding_master.call_forwardable_type == 'HuntGroup' && call_forwarding_master.call_forwardable - if call_forwarding_master.call_forwardable.hunt_group_members.where(:active => true).count > 0 + if call_forwarding_service = 'assistant' && call_forwarding_master.destinationable_type == 'HuntGroup' && call_forwarding_master.destinationable + if call_forwarding_master.destinationable.hunt_group_members.where(:active => true).count > 0 call_forwarding_master.active = true else call_forwarding_master.active = false @@ -105,7 +113,7 @@ class SipAccount < ActiveRecord::Base call_forwarding = phone_number.call_forwards.where(:call_forward_case_id => service_id).order(:active).all(:conditions => 'source IS NULL OR source = ""').first if ! call_forwarding call_forwarding = CallForward.new() - call_forwarding.phone_number_id = phone_number.id + call_forwarding.call_forwardable = phone_number end if to_voicemail == nil @@ -146,7 +154,7 @@ class SipAccount < ActiveRecord::Base true ); end - + private @@ -202,7 +210,7 @@ class SipAccount < ActiveRecord::Base # log out phone if sip_account is not on this node def log_out_phone_if_not_local - if self.gs_node_id && ! GsNode.where(:ip_address => GsParameter.get('HOMEBASE_IP_ADDRESS'), :id => self.gs_node_id).first + if self.gs_node_id && GsNode.count > 1 && ! GsNode.where(:ip_address => GsParameter.get('HOMEBASE_IP_ADDRESS'), :id => self.gs_node_id).first self.phones.each do |phone| phone.user_logout; end @@ -220,4 +228,29 @@ class SipAccount < ActiveRecord::Base voicemail_setting.purge = false voicemail_setting.save end + + def create_default_group_memberships + default_groups = Hash.new() + templates = GsParameter.get('SipAccount', 'group', 'default') + if templates.class == Array + templates.each do |group_name| + default_groups[group_name] = true + end + end + + templates = GsParameter.get("SipAccount.#{self.sip_accountable_type}", 'group', 'default') + if templates.class == Array + templates.each do |group_name| + default_groups[group_name] = true + end + end + + default_groups.each do |group_name, value| + group = Group.where(:name => group_name).first + if group + self.group_memberships.create(:group_id => group.id) + end + end + end + end diff --git a/app/models/softkey.rb b/app/models/softkey.rb index 4b758e0..8049456 100644 --- a/app/models/softkey.rb +++ b/app/models/softkey.rb @@ -30,7 +30,7 @@ class Softkey < ActiveRecord::Base # We pick one phone_number and display the rules of it. # phone_number = self.sip_account.phone_numbers.order(:number).first - call_forwards = self.sip_account.call_forwards.where(:phone_number_id => phone_number.id) + call_forwards = self.sip_account.call_forwards.where(:call_forwardable_id => phone_number.id, :call_forwardable_type => 'PhoneNumber') else call_forwards = self.sip_account.call_forwards end @@ -42,8 +42,8 @@ class Softkey < ActiveRecord::Base map{ |phone_number| phone_number.phone_numberable.hunt_group.id }. uniq - call_forwards + CallForward.where(:call_forwardable_type => 'HuntGroup', :call_forwardable_id => hunt_group_ids). - where('phone_number_id NOT IN (?)', phone_numbers_ids) + call_forwards + CallForward.where(:destinationable_type => 'HuntGroup', :destinationable_id => hunt_group_ids, :call_forwardable_type => 'PhoneNumber'). + where('call_forwardable_id NOT IN (?)', phone_numbers_ids) end end diff --git a/app/models/user.rb b/app/models/user.rb index 6c67351..913d75f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,7 @@ class User < ActiveRecord::Base # Sync other nodes when this is a cluster. # after_create :create_on_other_gs_nodes + after_create :create_default_group_memberships after_destroy :destroy_on_other_gs_nodes after_update :update_on_other_gs_nodes @@ -89,6 +90,9 @@ class User < ActiveRecord::Base belongs_to :gs_node has_many :parking_stalls, :as => :parking_stallable, :dependent => :destroy + + has_many :group_memberships, :as => :item, :dependent => :destroy, :uniq => true + has_many :groups, :through => :group_memberships # Avatar like photo mount_uploader :image, ImageUploader @@ -226,4 +230,16 @@ class User < ActiveRecord::Base end end + def create_default_group_memberships + templates = GsParameter.get('User', 'group', 'default') + if templates.class == Array + templates.each do |group_name| + group = Group.where(:name => group_name).first + if group + self.group_memberships.create(:group_id => group.id) + end + end + end + end + end diff --git a/app/uploaders/backup_file_uploader.rb b/app/uploaders/backup_file_uploader.rb index 8b126a9..0244ba5 100644 --- a/app/uploaders/backup_file_uploader.rb +++ b/app/uploaders/backup_file_uploader.rb @@ -42,9 +42,9 @@ class BackupFileUploader < CarrierWave::Uploader::Base # 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 + def extension_white_list + %w(tar.gz) + end # Override the filename of the uploaded files: # Avoid using model.id or version_name here, see uploader/store.rb for details. diff --git a/app/uploaders/fax_document_uploader.rb b/app/uploaders/fax_document_uploader.rb new file mode 100644 index 0000000..bfb7e07 --- /dev/null +++ b/app/uploaders/fax_document_uploader.rb @@ -0,0 +1,19 @@ +# encoding: utf-8 + +class FaxDocumentUploader < CarrierWave::Uploader::Base + include CarrierWave::MiniMagick + + storage :file + + def store_dir + model.store_dir + end + + def cache_dir + '/tmp/gs_fax_uploader' + end + + def extension_white_list + %w(pdf ps jpg jpeg gif png tif tiff) + end +end diff --git a/app/views/backup_jobs/show.html.haml b/app/views/backup_jobs/show.html.haml index 6fcb1dc..8bb270f 100644 --- a/app/views/backup_jobs/show.html.haml +++ b/app/views/backup_jobs/show.html.haml @@ -1,22 +1,34 @@ - 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) +%table.table.table-striped + %tbody + %tr + %td + %strong= t('backup_jobs.show.started_at') + ":" + %td + = @backup_job.started_at + %tr + %td + %strong= t('backup_jobs.show.finished_at') + ":" + %td + = @backup_job.finished_at + %tr + %td + %strong= t('backup_jobs.show.state') + ":" + %td + = @backup_job.state + %tr + %td + %strong= t('backup_jobs.show.directory') + ":" + %td + = @backup_job.directory + %tr + %td + %strong= t('backup_jobs.show.size_of_the_backup') + ":" + %td + - 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_forwards/_form.html.haml b/app/views/call_forwards/_form.html.haml index 58ffd78..1944fc4 100644 --- a/app/views/call_forwards/_form.html.haml +++ b/app/views/call_forwards/_form.html.haml @@ -1,4 +1,4 @@ -= simple_form_for([ @phone_number, @call_forward ]) do |f| += simple_form_for([ @parent, @call_forward ]) do |f| = f.error_notification = render "form_core", :f => f diff --git a/app/views/call_forwards/_form_core.html.haml b/app/views/call_forwards/_form_core.html.haml index b751fb3..83de044 100644 --- a/app/views/call_forwards/_form_core.html.haml +++ b/app/views/call_forwards/_form_core.html.haml @@ -1,5 +1,5 @@ .inputs - = f.input :call_forward_case_id, :as => :select, :collection => @available_call_forward_cases.map {|x| [I18n.t("call_forward_cases.#{x.value}"), x.id] }, :label => t('call_forwards.form.call_forward_case_id.label'), :hint => conditional_hint('call_forwards.form.call_forward_case_id.hint'), :include_blank => false, :autofocus => true + = f.input :call_forward_case_id, :as => :select, :collection => @available_call_forward_cases.map {|x| [I18n.t("call_forward_cases.#{x.value}"), x.id] }, :label => t('call_forwards.form.call_forward_case.label'), :hint => conditional_hint('call_forwards.form.call_forward_case_id.hint'), :include_blank => false, :autofocus => true = f.input :timeout, :label => t('call_forwards.form.timeout.label'), :hint => conditional_hint('call_forwards.form.timeout.hint') = f.input :call_forwarding_destination , :as => :select, :collection => @call_forwarding_destinations, :label => t('call_forwards.form.call_forwarding_destination.label'), :hint => conditional_hint('call_forwards.form.call_forwarding_destination.hint'), :include_blank => false @@ -8,8 +8,4 @@ = f.input :source, :label => t('call_forwards.form.source.label'), :hint => conditional_hint('call_forwards.form.source.hint') - - if GuiFunction.display?('depth_field_in_call_forward_form', current_user) - = f.input :depth, :collection => 1..GsParameter.get('MAX_CALL_FORWARD_DEPTH'), :label => t('call_forwards.form.depth.label'), :hint => conditional_hint('call_forwards.form.depth.hint') - - else - = f.hidden_field :depth = f.input :active, :label => t('call_forwards.form.active.label'), :hint => conditional_hint('call_forwards.form.active.hint') diff --git a/app/views/call_forwards/_index_core.html.haml b/app/views/call_forwards/_index_core.html.haml index 878e0e2..3c57405 100644 --- a/app/views/call_forwards/_index_core.html.haml +++ b/app/views/call_forwards/_index_core.html.haml @@ -1,32 +1,29 @@ %table.table.table-striped %thead %tr - - if !@phone_number - %th= t('call_forwards.index.phone_number_id') - %th= t('call_forwards.index.call_forward_case_id') + %th + %th= t('call_forwards.index.call_forward_case') %th= t('call_forwards.index.timeout') %th= t('call_forwards.index.destination') - %th= t('call_forwards.index.source') - - if GuiFunction.display?('depth_field_value_in_index_table', current_user) - %th= t('call_forwards.index.depth') - %th= t('call_forwards.index.active') + %th= t('call_forwards.index.source') %tbody - for call_forward in call_forwards %tr - - if !@phone_number - %td= call_forward.phone_number + %td + -if call_forward.active + %i.icon-ok + - else + %i.icon-ban-circle %td= t("call_forward_cases.#{call_forward.call_forward_case.value}") %td= call_forward.timeout %td = call_forward.destination - - if call_forward.call_forwardable_type + - if call_forward.destinationable_type %br - = call_forward.call_forwardable_type - - if call_forward.call_forwardable - = ": #{call_forward.call_forwardable}" + = call_forward.destinationable_type + - if call_forward.destinationable_id + = ": #{call_forward.destinationable}" %td= call_forward.source - - if GuiFunction.display?('depth_field_value_in_index_table', current_user) - %td= call_forward.depth - %td= call_forward.active - =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => call_forward.phone_number, :child => call_forward}
\ No newline at end of file + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => call_forward.call_forwardable, :child => call_forward} + diff --git a/app/views/call_forwards/index.html.haml b/app/views/call_forwards/index.html.haml index 91b923a..e206653 100644 --- a/app/views/call_forwards/index.html.haml +++ b/app/views/call_forwards/index.html.haml @@ -3,4 +3,4 @@ - if @call_forwards.count > 0 = render "index_core", :call_forwards => @call_forwards -= render :partial => 'shared/create_link', :locals => {:parent => @phone_number, :child_class => CallForward}
\ No newline at end of file += render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => CallForward}
\ No newline at end of file diff --git a/app/views/call_forwards/show.html.haml b/app/views/call_forwards/show.html.haml index c2187b1..ad9ab16 100644 --- a/app/views/call_forwards/show.html.haml +++ b/app/views/call_forwards/show.html.haml @@ -1,33 +1,25 @@ - content_for :title, t("call_forwards.show.page_title") %p - %strong= t('call_forwards.show.phone_number_id') + ":" - = @call_forward.phone_number -%p - %strong= t('call_forwards.show.call_forward_case_id') + ":" + %strong= t('call_forwards.show.call_forward_case') + ":" = t("call_forward_cases.#{@call_forward.call_forward_case.value}") %p %strong= t('call_forwards.show.timeout') + ":" = @call_forward.timeout %p %strong= t('call_forwards.show.destination') + ":" - = @call_forward.destination -- if @call_forward.call_forwardable_type == 'HuntGroup' && @call_forward.call_forwardable.class == HuntGroup - %p - %strong= t('call_forwards.show.hunt_group') + ":" - = @call_forward.call_forwardable -- if @call_forward.call_forwardable_type == 'Voicemail' - %p - %strong= t('call_forwards.show.to_voicemail') + ":" - = 'active' + - if @call_forward.destinationable_id && @call_forward.destinationable + = "#{@call_forward.destinationable_type}: #{@call_forward.destinationable}" + - elsif !@call_forward.destinationable_type.blank? + = "#{@call_forward.destinationable_type}: #{@call_forward.destination}" + - else + = @call_forward.destination + %p %strong= t('call_forwards.show.source') + ":" = @call_forward.source %p - %strong= t('call_forwards.show.depth') + ":" - = @call_forward.depth -%p %strong= t('call_forwards.show.active') + ":" = @call_forward.active -= render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number, :child => @call_forward }
\ No newline at end of file += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @parent, :child => @call_forward } diff --git a/app/views/calls/_form.html.haml b/app/views/calls/_form.html.haml new file mode 100644 index 0000000..ccdcd72 --- /dev/null +++ b/app/views/calls/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([ @parent, @call ]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .form-actions + = f.button :submit, conditional_t('calls.form.submit') diff --git a/app/views/calls/_form_core.html.haml b/app/views/calls/_form_core.html.haml new file mode 100644 index 0000000..4cdd55e --- /dev/null +++ b/app/views/calls/_form_core.html.haml @@ -0,0 +1,2 @@ +.inputs + = f.input :dest, :as => :string, :label => t('calls.form.destination.label'), :hint => conditional_hint('calls.form.destination.hint'), :autofocus => true diff --git a/app/views/calls/_index_core.html.haml b/app/views/calls/_index_core.html.haml index 10f79f1..e5b769e 100644 --- a/app/views/calls/_index_core.html.haml +++ b/app/views/calls/_index_core.html.haml @@ -1,10 +1,38 @@ %table.table.table-striped %thead %tr - %th= t('calls.index.uuid') + %th + %th= t('calls.index.created') + %th= t('calls.index.destination') + %th= t('calls.index.caller') + %th= t('calls.index.callee') + %th= t('calls.index.callstate') + %th= t('calls.index.codecs') + %th %tbody - - for call in @calls + - for call in calls %tr %td - = call.uuid + - if call.direction == 'inbound' + %i.icon-arrow-left + - else + %i.icon-arrow-right + %td + = call.created + %td + = call.dest + %td + = "#{call.cid_name} #{call.cid_num}" + %td + = "#{call.callee_name} #{call.callee_num}" + %td + = call.callstate + %td + = "#{call.read_codec}/#{call.write_codec}" + + %td + %p + %a.btn.btn-small.btn-danger{'data-confirm' => t('calls.index.actions.confirm_destroy'), 'data-method' => 'delete', :href => method( :"#{parent.class.name.underscore}_call_path" ).(parent, call), :rel => 'nofollow'} + %i.icon-trash.icon-white + =t('calls.index.actions.destroy') diff --git a/app/views/calls/index.html.haml b/app/views/calls/index.html.haml index be678cd..a87f809 100644 --- a/app/views/calls/index.html.haml +++ b/app/views/calls/index.html.haml @@ -1,6 +1,8 @@ - content_for :title, t("calls.index.page_title") - if @calls.count > 0 - = render "index_core", :calls => @calls + = render "index_core", :calls => @calls, :parent => @parent -= render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Call}
\ No newline at end of file +%a.btn.btn-small.btn-default{:href => method( :"new_#{@parent.class.name.underscore}_call_path" ).(@parent) } + %i.icon-plus + =t("calls.index.actions.create") diff --git a/app/views/calls/new.html.haml b/app/views/calls/new.html.haml new file mode 100644 index 0000000..44bb6ae --- /dev/null +++ b/app/views/calls/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("calls.new.page_title") + += render "form" diff --git a/app/views/fax_documents/_index_core.html.haml b/app/views/fax_documents/_index_core.html.haml index 5355521..2f9b214 100644 --- a/app/views/fax_documents/_index_core.html.haml +++ b/app/views/fax_documents/_index_core.html.haml @@ -50,7 +50,7 @@ - if fax_document.document? %p - %a{:href => fax_document.document.url} + %a{:href => fax_account_fax_document_path(@fax_account, fax_document, :format => :pdf), :method => :get} %i{:class => 'icon-download'} = t("fax_documents.index.actions.download_pdf") + " (#{number_to_human_size(fax_document.document.size, :precision => 2)})" diff --git a/app/views/fax_documents/show.html.haml b/app/views/fax_documents/show.html.haml index 9925c2f..b8f3e9e 100644 --- a/app/views/fax_documents/show.html.haml +++ b/app/views/fax_documents/show.html.haml @@ -46,7 +46,7 @@ - if @fax_document.document? %p - %a{:href => @fax_document.document.url} + %a{:href => fax_account_fax_document_path(@fax_account, @fax_document, :format => :pdf), :method => :get} %i{:class => 'icon-download'} = t("fax_documents.index.actions.download_pdf") + " (#{number_to_human_size(@fax_document.document.size, :precision => 2)})" diff --git a/app/views/group_memberships/_form.html.haml b/app/views/group_memberships/_form.html.haml new file mode 100644 index 0000000..c8a6a51 --- /dev/null +++ b/app/views/group_memberships/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@group, @group_membership]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .form-actions + = f.button :submit, conditional_t('group_memberships.form.submit') diff --git a/app/views/group_memberships/_form_core.html.haml b/app/views/group_memberships/_form_core.html.haml new file mode 100644 index 0000000..4a28a06 --- /dev/null +++ b/app/views/group_memberships/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs + - if @group.group_memberships.count < 1 + = f.input :item_type, :label => t('group_memberships.form.item_type.label'), :hint => conditional_hint('group_memberships.form.item_type.hint') + = f.input :item_id, :label => t('group_memberships.form.item_id.label'), :hint => conditional_hint('group_memberships.form.item_id.hint') diff --git a/app/views/group_memberships/_index_core.html.haml b/app/views/group_memberships/_index_core.html.haml new file mode 100644 index 0000000..beeefc9 --- /dev/null +++ b/app/views/group_memberships/_index_core.html.haml @@ -0,0 +1,11 @@ +%table.table.table-striped + %tr + %th= t('group_memberships.index.item_type') + %th= t('group_memberships.index.item_id') + + + - for group_membership in group_memberships + %tr + %td= group_membership.item_type + %td= group_membership.item_id + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => group_membership.group, :child => group_membership} diff --git a/app/views/group_memberships/edit.html.haml b/app/views/group_memberships/edit.html.haml new file mode 100644 index 0000000..643c095 --- /dev/null +++ b/app/views/group_memberships/edit.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("group_memberships.edit.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/group_memberships/index.html.haml b/app/views/group_memberships/index.html.haml new file mode 100644 index 0000000..b493017 --- /dev/null +++ b/app/views/group_memberships/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("group_memberships.index.page_title") + +- if @group_memberships && @group_memberships.count > 0 + = render "index_core", :group_memberships => @group_memberships + += render :partial => 'shared/create_link', :locals => {:parent => @group, :child_class => GroupMembership} diff --git a/app/views/group_memberships/new.html.haml b/app/views/group_memberships/new.html.haml new file mode 100644 index 0000000..6cf2ce7 --- /dev/null +++ b/app/views/group_memberships/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("group_memberships.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/group_memberships/show.html.haml b/app/views/group_memberships/show.html.haml new file mode 100644 index 0000000..0875f0b --- /dev/null +++ b/app/views/group_memberships/show.html.haml @@ -0,0 +1,10 @@ +- content_for :title, t("group_memberships.show.page_title") + +%p + %strong= t('group_memberships.show.item_type') + ":" + = @group_membership.item_type +%p + %strong= t('group_memberships.show.item_id') + ":" + = @group_membership.item_id + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @group, :child => @group_membership } diff --git a/app/views/group_permissions/_form.html.haml b/app/views/group_permissions/_form.html.haml new file mode 100644 index 0000000..5f593f2 --- /dev/null +++ b/app/views/group_permissions/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for([@group, @group_permission]) do |f| + = f.error_notification + + = render "form_core", :f => f + + .form-actions + = f.button :submit, conditional_t('group_permissions.form.submit') diff --git a/app/views/group_permissions/_form_core.html.haml b/app/views/group_permissions/_form_core.html.haml new file mode 100644 index 0000000..49c9e7c --- /dev/null +++ b/app/views/group_permissions/_form_core.html.haml @@ -0,0 +1,3 @@ +.inputs + = f.input :permission, :collection => GroupPermission::PERMISSION_TYPES, :label => t('group_permissions.form.permission.label'), :hint => conditional_hint('group_permissions.form.permission.hint'), :include_blank => false + = f.input :target_group_id, :collection => Group.all.collect, :label => t('group_permissions.form.target_group_id.label'), :hint => conditional_hint('group_permissions.form.target_group_id.hint'), :include_blank => false diff --git a/app/views/group_permissions/_index_core.html.haml b/app/views/group_permissions/_index_core.html.haml new file mode 100644 index 0000000..ad06b38 --- /dev/null +++ b/app/views/group_permissions/_index_core.html.haml @@ -0,0 +1,11 @@ +%table.table.table-striped + %tr + %th= t('group_permissions.index.permission') + %th= t('group_permissions.index.target_group_id') + + + - for group_permission in group_permissions + %tr + %td= group_permission.permission + %td= group_permission.target_group + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => group_permission.group, :child => group_permission} diff --git a/app/views/group_permissions/edit.html.haml b/app/views/group_permissions/edit.html.haml new file mode 100644 index 0000000..c673eea --- /dev/null +++ b/app/views/group_permissions/edit.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("group_permissions.edit.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/group_permissions/index.html.haml b/app/views/group_permissions/index.html.haml new file mode 100644 index 0000000..0bc0c37 --- /dev/null +++ b/app/views/group_permissions/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("group_permissions.index.page_title") + +- if @group_permissions && @group_permissions.count > 0 + = render "index_core", :group_permissions => @group_permissions + += render :partial => 'shared/create_link', :locals => {:parent => @group, :child_class => GroupPermission}
\ No newline at end of file diff --git a/app/views/group_permissions/new.html.haml b/app/views/group_permissions/new.html.haml new file mode 100644 index 0000000..8012273 --- /dev/null +++ b/app/views/group_permissions/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("group_permissions.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/group_permissions/show.html.haml b/app/views/group_permissions/show.html.haml new file mode 100644 index 0000000..402c5ce --- /dev/null +++ b/app/views/group_permissions/show.html.haml @@ -0,0 +1,10 @@ +- content_for :title, t("group_permissions.show.page_title") + +%p + %strong= t('group_permissions.show.permission') + ":" + = @group_permission.permission +%p + %strong= t('group_permissions.show.target_group_id') + ":" + = @group_permission.target_group_id + += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @group, :child => @group_permission } diff --git a/app/views/groups/_form.html.haml b/app/views/groups/_form.html.haml new file mode 100644 index 0000000..f5bdece --- /dev/null +++ b/app/views/groups/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@group) do |f| + = f.error_notification + + = render "form_core", :f => f + + .form-actions + = f.button :submit, conditional_t('groups.form.submit') diff --git a/app/views/groups/_form_core.html.haml b/app/views/groups/_form_core.html.haml new file mode 100644 index 0000000..1f9a39f --- /dev/null +++ b/app/views/groups/_form_core.html.haml @@ -0,0 +1,4 @@ +.inputs + = f.input :name, :label => t('groups.form.name.label'), :hint => conditional_hint('groups.form.name.hint') + = f.input :active, :label => t('groups.form.active.label'), :hint => conditional_hint('groups.form.active.hint') + = f.input :comment, :label => t('groups.form.comment.label'), :hint => conditional_hint('groups.form.comment.hint') diff --git a/app/views/groups/_index_core.html.haml b/app/views/groups/_index_core.html.haml new file mode 100644 index 0000000..3a444bf --- /dev/null +++ b/app/views/groups/_index_core.html.haml @@ -0,0 +1,17 @@ +%table.table.table-striped + %tr + %th + %th= t('groups.index.name') + %th= t('groups.index.comment') + + + - for group in groups + %tr + %td + -if group.active + %i.icon-ok + - else + %i.icon-ban-circle + %td= group.name + %td= group.comment + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => group}
\ No newline at end of file diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml new file mode 100644 index 0000000..7a3f784 --- /dev/null +++ b/app/views/groups/edit.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("groups.edit.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/groups/index.html.haml b/app/views/groups/index.html.haml new file mode 100644 index 0000000..7984b9e --- /dev/null +++ b/app/views/groups/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("groups.index.page_title") + +- if @groups && @groups.count > 0 + = render "index_core", :groups => @groups + += render :partial => 'shared/create_link', :locals => {:child_class => Group}
\ No newline at end of file diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml new file mode 100644 index 0000000..e8017a8 --- /dev/null +++ b/app/views/groups/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("groups.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml new file mode 100644 index 0000000..fc291f3 --- /dev/null +++ b/app/views/groups/show.html.haml @@ -0,0 +1,25 @@ +- content_for :title, t("groups.show.page_title") + +%p + %strong= t('groups.show.name') + ":" + = @group.name +%p + %strong= t('groups.show.active') + ":" + = @group.active +%p + %strong= t('groups.show.comment') + ":" + = @group.comment + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @group } + +%h3= t('group_permissions.index.page_title') +- if @group.group_permissions.any? + = render "group_permissions/index_core", :group_permissions => @group.group_permissions + %br += render :partial => 'shared/create_link', :locals => { :parent => @group, :child_class => GroupPermission } + +%h3= t('group_memberships.index.page_title') +- if @group.group_memberships.any? + = render "group_memberships/index_core", :group_memberships => @group.group_memberships + %br += render :partial => 'shared/create_link', :locals => { :parent => @group, :child_class => GroupMembership } diff --git a/app/views/gs_nodes/sync.xml.haml b/app/views/gs_nodes/sync.xml.haml index a2fa71a..bba5c4e 100644 --- a/app/views/gs_nodes/sync.xml.haml +++ b/app/views/gs_nodes/sync.xml.haml @@ -55,7 +55,7 @@ - if !@call_forwards.blank? %call_forwards - @call_forwards.each do |call_forward| - %call_forward{ :uuid => call_forward.uuid, :service => call_forward.call_forward_case.try(:value), :timeout => call_forward.timeout, :destination => call_forward.destination, :source => call_forward.source, :active => call_forward.active.to_s, :created_at => call_forward.created_at, :updated_at => call_forward.updated_at, :phone_number_uuid => call_forward.phone_number.try(:uuid), :depth => call_forward.depth, :call_forwardable_type => call_forward.call_forwardable_type, :call_forwardable_uuid => call_forward.call_forwardable.try(:uuid), :position => call_forward.position} + %call_forward{ :uuid => call_forward.uuid, :service => call_forward.call_forward_case.try(:value), :timeout => call_forward.timeout, :destination => call_forward.destination, :source => call_forward.source, :active => call_forward.active.to_s, :created_at => call_forward.created_at, :updated_at => call_forward.updated_at, :phone_number_uuid => call_forward.phone_number.try(:uuid), :depth => call_forward.depth, :call_forwardable_type => call_forward.call_forwardable_type, :call_forwardable_uuid => call_forward.call_forwardable.try(:uuid), :destinationable_type => call_forward.destinationable_type, :destinationable_uuid => call_forward.destinationable.try(:uuid), :position => call_forward.position} - if !@softkeys.blank? %softkeys diff --git a/app/views/intruders/_index_core.html.haml b/app/views/intruders/_index_core.html.haml index 31bbd11..63f2253 100644 --- a/app/views/intruders/_index_core.html.haml +++ b/app/views/intruders/_index_core.html.haml @@ -16,7 +16,14 @@ - for intruder in intruders %tr - %td= intruder.list_type.chars.first + %td + - if intruder.list_type == 'whitelist' + %i.icon-ok + - elsif intruder.bans > 0 + %i.icon-fire + - elsif intruder.points > 0 + %i.icon-warning-sign + %td= intruder.contact_ip %td= intruder.contact_port %td= intruder.points diff --git a/app/views/layouts/_navbar.html.haml b/app/views/layouts/_navbar.html.haml index 8e09859..8004c0e 100644 --- a/app/views/layouts/_navbar.html.haml +++ b/app/views/layouts/_navbar.html.haml @@ -1,16 +1,14 @@ .navbar.navbar-inverse.navbar-fixed-top .navbar-inner .container - %a.brand{:href => (current_user.nil? ? '/' : tenant_path(current_user.current_tenant))} - Gemeinschaft 5 - - %a.btn.btn-navbar{"data-target" => ".nav-collapse", "data-toggle" => "collapse"} - %span.icon-bar - %span.icon-bar - %span.icon-bar + %span.hidden-phone + %a.brand{:href => (current_user.nil? ? '/' : tenant_path(current_user.current_tenant))} + Gemeinschaft 5.1 .nav-collapse.collapse %ul.nav + - if !GemeinschaftSetup.any? + %li=link_to t('restore_jobs.new.page_title'), new_restore_job_path - if current_user && GemeinschaftSetup.any? && current_user.admin? - if current_page?(page_help_path) %li.active @@ -29,13 +27,14 @@ - if current_user %ul.nav.pull-right %li.display - - if current_user.image? - = image_tag(current_user.image_url(:mini).to_s, :class => 'img-rounded') - - else - - if current_user.male? - = image_tag 'icons/user-male-16x.png', :class => 'img-rounded' + %span.hidden-phone + - if current_user.image? + = image_tag(current_user.image_url(:mini).to_s, :class => 'img-rounded') - else - = image_tag 'icons/user-female-16x.png', :class => 'img-rounded' + - if current_user.male? + = image_tag 'icons/user-male-16x.png', :class => 'img-rounded' + - else + = image_tag 'icons/user-female-16x.png', :class => 'img-rounded' - if current_page?(tenant_user_path(current_user.current_tenant, current_user)) %li.active @@ -51,3 +50,7 @@ %a.navbar-link{:href => log_out_path} %i.icon-off.icon-white + - if GuiFunction.display?('search_field_in_top_navigation_bar', current_user) + = form_tag search_path, :method => :post, :class => 'navbar-search pull-right' do + %input.text{:placeholder => 'Suchen ...', :name => 'q', :class => 'search-query span2'} + diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 33a730f..eab6096 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -3,7 +3,7 @@ %head %meta{:charset => "utf-8"}/ %title - = content_for?(:title) ? yield(:title) : "Gemeinschaft 5" + = content_for?(:title) ? yield(:title) : "Gemeinschaft 5.1" %meta{:name => 'viewport', :content => "width=device-width, initial-scale=1.0"} - if content_for?(:meta_description) %meta{:description => yield(:meta_description)}/ diff --git a/app/views/phone_books/_index_core.html.haml b/app/views/phone_books/_index_core.html.haml index 09ce3a3..290a12e 100644 --- a/app/views/phone_books/_index_core.html.haml +++ b/app/views/phone_books/_index_core.html.haml @@ -5,7 +5,9 @@ %th %span.visible-desktop = t('phone_books.index.description') - %th= t('phone_books.index.count') + %th + %span.visible-desktop + = t('phone_books.index.count') %tbody - for phone_book in phone_books @@ -16,6 +18,7 @@ %span.visible-desktop = phone_book.description %td - = number_with_delimiter( phone_book.phone_book_entries.count ) + %span.visible-desktop + = number_with_delimiter( phone_book.phone_book_entries.count ) =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => phone_book.phone_bookable, :child => phone_book}
\ No newline at end of file diff --git a/app/views/phone_numbers/_form_core.html.haml b/app/views/phone_numbers/_form_core.html.haml index a0a69db..1589e7e 100644 --- a/app/views/phone_numbers/_form_core.html.haml +++ b/app/views/phone_numbers/_form_core.html.haml @@ -1,7 +1,7 @@ .inputs - if @phone_book_entry - = 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 :name, :collection => PhoneBookEntry::PHONE_NUMBER_NAMES, :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 diff --git a/app/views/phone_numbers/show.html.haml b/app/views/phone_numbers/show.html.haml index de6cb1b..9fe6ea4 100644 --- a/app/views/phone_numbers/show.html.haml +++ b/app/views/phone_numbers/show.html.haml @@ -9,15 +9,16 @@ %strong= t('phone_numbers.show.number') + ":" = @phone_number.to_s += render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number.phone_numberable, :child => @phone_number } + - if @ringtoneable_classes.has_key?(@phone_number.phone_numberable.class.to_s) %p - %strong= t('ringtones.name') + ':' - - if @phone_number.ringtones.count > 0 - = link_to @phone_number.ringtones.first, phone_number_ringtone_path(@phone_number, @phone_number.ringtones.first) - - else - = link_to t('ringtones.set_a_ringtone'), new_phone_number_ringtone_path(@phone_number) - -= render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number.phone_numberable, :child => @phone_number } + %strong= t('ringtones.name') + ':' + - if @phone_number.ringtones.count > 0 + = @phone_number.ringtones.first + = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @phone_number, :child => @phone_number.ringtones.first } + - else + = render :partial => 'shared/create_link', :locals => { :parent => @phone_number, :child_class => Ringtone } - if @forwardable_classes.has_key?(@phone_number.phone_numberable.class.to_s) %h3= t("call_forwards.index.page_title") diff --git a/app/views/restore_jobs/_form.html.haml b/app/views/restore_jobs/_form.html.haml new file mode 100644 index 0000000..43ced9a --- /dev/null +++ b/app/views/restore_jobs/_form.html.haml @@ -0,0 +1,7 @@ += simple_form_for(@restore_job) do |f| + = f.error_notification + + = render "form_core", :f => f + + .form-actions + = f.button :submit, conditional_t('restore_jobs.form.submit') diff --git a/app/views/restore_jobs/_form_core.html.haml b/app/views/restore_jobs/_form_core.html.haml new file mode 100644 index 0000000..017c124 --- /dev/null +++ b/app/views/restore_jobs/_form_core.html.haml @@ -0,0 +1,2 @@ +.inputs + = f.input :backup_file, :label => t('restore_jobs.form.backup_file.label'), :hint => conditional_hint('restore_jobs.form.backup_file.hint') diff --git a/app/views/restore_jobs/_index_core.html.haml b/app/views/restore_jobs/_index_core.html.haml new file mode 100644 index 0000000..f6127ba --- /dev/null +++ b/app/views/restore_jobs/_index_core.html.haml @@ -0,0 +1,12 @@ +%table.table.table-striped + %tr + %th= t('restore_jobs.index.state') + %th= t('restore_jobs.index.backup_file') + %th + + + - for restore_job in restore_jobs + %tr + %td= restore_job.state + %td= restore_job.to_s + =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:child => restore_job}
\ No newline at end of file diff --git a/app/views/restore_jobs/index.html.haml b/app/views/restore_jobs/index.html.haml new file mode 100644 index 0000000..b8aa74e --- /dev/null +++ b/app/views/restore_jobs/index.html.haml @@ -0,0 +1,6 @@ +- content_for :title, t("restore_jobs.index.page_title") + +- if @restore_jobs && @restore_jobs.count > 0 + = render "index_core", :restore_jobs => @restore_jobs + += render :partial => 'shared/create_link', :locals => {:child_class => RestoreJob}
\ No newline at end of file diff --git a/app/views/restore_jobs/new.html.haml b/app/views/restore_jobs/new.html.haml new file mode 100644 index 0000000..ffae792 --- /dev/null +++ b/app/views/restore_jobs/new.html.haml @@ -0,0 +1,3 @@ +- content_for :title, t("restore_jobs.new.page_title") + += render "form"
\ No newline at end of file diff --git a/app/views/restore_jobs/show.html.haml b/app/views/restore_jobs/show.html.haml new file mode 100644 index 0000000..5993872 --- /dev/null +++ b/app/views/restore_jobs/show.html.haml @@ -0,0 +1,22 @@ +- content_for :title, t("restore_jobs.show.page_title") + +%table.table.table-striped + %tbody + %tr + %td + %strong= t('restore_jobs.show.state') + ":" + %td + = @restore_job.state + %tr + %td + %strong= t('restore_jobs.show.backup_file') + ":" + %td + = @restore_job.to_s + %tr + %td + %strong= t('backup_jobs.show.size_of_the_backup') + ":" + %td + - if @restore_job.backup_file? + = number_to_human_size(@restore_job.backup_file.size, :precision => 2) + += render :partial => 'shared/show_edit_destroy_part', :locals => { :child => @restore_job }
\ No newline at end of file diff --git a/app/views/ringtones/_form_core.html.haml b/app/views/ringtones/_form_core.html.haml index e44c950..de1cc38 100644 --- a/app/views/ringtones/_form_core.html.haml +++ b/app/views/ringtones/_form_core.html.haml @@ -1,3 +1,3 @@ .inputs / = f.input :audio, :label => t('ringtones.form.audio.label'), :hint => conditional_hint('ringtones.form.audio.hint') - = f.input :bellcore_id, :collection => 0..10, :label => t('ringtones.form.bellcore_id.label'), :hint => conditional_hint('ringtones.form.bellcore_id.hint'), :include_blank => true + = f.input :bellcore_id, :collection => Ringtone::CORE_RINGTONES_AVAILABLE, :label => t('ringtones.form.bellcore_id.label'), :hint => conditional_hint('ringtones.form.bellcore_id.hint'), :include_blank => false diff --git a/app/views/ringtones/_index_core.html.haml b/app/views/ringtones/_index_core.html.haml index 715db3c..51347a5 100644 --- a/app/views/ringtones/_index_core.html.haml +++ b/app/views/ringtones/_index_core.html.haml @@ -1,12 +1,12 @@ %table.table.table-striped %thead %tr - %th= t('ringtones.index.audio') + /%th= t('ringtones.index.audio') %th= t('ringtones.index.bellcore_id') %tbody - for ringtone in ringtones %tr - %td= ringtone.audio + /%td= ringtone.audio %td= ringtone.bellcore_id =render :partial => 'shared/index_view_edit_destroy_part', :locals => {:parent => ringtone.ringtoneable, :child => ringtone}
\ No newline at end of file diff --git a/app/views/ringtones/index.html.haml b/app/views/ringtones/index.html.haml index 2eea5fe..2e316a5 100644 --- a/app/views/ringtones/index.html.haml +++ b/app/views/ringtones/index.html.haml @@ -2,5 +2,5 @@ - if @ringtones.count > 0 = render "index_core", :ringtones => @ringtones - -= render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Ringtone}
\ No newline at end of file +- else + = render :partial => 'shared/create_link', :locals => {:parent => @parent, :child_class => Ringtone}
\ No newline at end of file diff --git a/app/views/sessions/new.html.haml b/app/views/sessions/new.html.haml index 75dd3de..0c5c96d 100644 --- a/app/views/sessions/new.html.haml +++ b/app/views/sessions/new.html.haml @@ -1,8 +1,12 @@ - content_for :title, t("sessions.new.page_title") -= simple_form_for :sessions, :url => sessions_path do |t| - = t.input :login_data, :label => t('sessions.form.email'), :autofocus => true - = t.input :password, :label => t('sessions.form.password'), :required => false - = t.input :reset_password, :label => t('sessions.form.reset_password'), :as => :boolean - .form-actions - = t.button :submit, :value => 'Login' +.row + .span12 + %h1=t("sessions.new.page_title") + + = simple_form_for :sessions, :url => sessions_path do |t| + = t.input :login_data, :label => t('sessions.form.email'), :autofocus => true + = t.input :password, :label => t('sessions.form.password'), :required => false + = t.input :reset_password, :label => t('sessions.form.reset_password'), :as => :boolean + .form-actions + = t.button :submit, :value => 'Login' diff --git a/app/views/sip_accounts/_form_core.html.haml b/app/views/sip_accounts/_form_core.html.haml index 1a8876a..d7c65d0 100644 --- a/app/views/sip_accounts/_form_core.html.haml +++ b/app/views/sip_accounts/_form_core.html.haml @@ -13,6 +13,4 @@ - if @sip_account.sip_accountable_type == 'User' = f.input :hotdeskable, :label => t('sip_accounts.form.hotdeskable.label'), :hint => conditional_hint('sip_accounts.form.hotdeskable.hint') = f.input :clip_no_screening, :label => t('sip_accounts.form.clip_no_screening.label'), :hint => conditional_hint('sip_accounts.form.clip_no_screening.hint') - - if CallForward.where(:phone_number_id => @sip_account.phone_number_ids).count == 0 || @sip_account.callforward_rules_act_per_sip_account == true - = f.input :callforward_rules_act_per_sip_account, :label => t('sip_accounts.form.callforward_rules_act_per_sip_account.label'), :hint => conditional_hint('sip_accounts.form.callforward_rules_act_per_sip_account.hint') = f.input :language_code, :collection => Language.all.collect{|l| [l.to_s, l.code]}, :label => t('sip_accounts.form.language_code.label'), :hint => conditional_hint('sip_accounts.form.language_id.hint'), :include_blank => false diff --git a/app/views/sip_accounts/_index_core.html.haml b/app/views/sip_accounts/_index_core.html.haml index 34aac64..d98ea0a 100644 --- a/app/views/sip_accounts/_index_core.html.haml +++ b/app/views/sip_accounts/_index_core.html.haml @@ -20,13 +20,13 @@ - if sip_account.registration %i.icon-ok - else - %i.icon-thumbs-down + %i.icon-ban-circle %td = sip_account.caller_name - phone_numbers = sip_account.phone_numbers %td - if sip_account.phone_numbers.count > 0 - = render 'phone_numbers/listing', :phone_numbers => sip_account.phone_numbers.order(:number) + = render 'phone_numbers/listing', :phone_numbers => sip_account.phone_numbers.order(:position) - if sip_accounts.map{ |sip_account| sip_account.phone_sip_accounts.any? }.include?(true) %td %span.hidden-phone diff --git a/app/views/sip_accounts/show.html.haml b/app/views/sip_accounts/show.html.haml index 72e10df..365aea8 100644 --- a/app/views/sip_accounts/show.html.haml +++ b/app/views/sip_accounts/show.html.haml @@ -37,11 +37,6 @@ %strong= t('sip_accounts.show.hotdeskable') + ":" %td = @sip_account.hotdeskable == true ? t('simple_form.yes') : t('simple_form.no') - %tr - %td - %strong= t('sip_accounts.show.callforward_rules_act_per_sip_account') + ":" - %td - = @sip_account.callforward_rules_act_per_sip_account == true ? t('simple_form.yes') : t('simple_form.no') - if @sip_account.registration.try(:network_ip) && @sip_account.registration.try(:network_port) %tr @@ -65,6 +60,21 @@ = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @sip_account.sip_accountable, :child => @sip_account } +%p + %strong= t('sip_accounts.show.tel_protocol') + ':' +%p + %a.btn.btn-small.btn-default{ :href => '', :onclick => "navigator.registerProtocolHandler(\"tel\", \"#{@register_tel_protocol}\", \"#{@sip_account.to_s}\");" } + %i.icon-plus + = t('sip_accounts.show.register_tel_protocol') + +%p + %strong= t('ringtones.name') + ':' + - if @sip_account.ringtones.count > 0 + = @sip_account.ringtones.first + = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @sip_account, :child => @sip_account.ringtones.first } + - else + = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => Ringtone } + - if @sip_account.phone_numbers.count > 0 || can?(:create, @sip_account.phone_numbers.build) %h2= t('phone_numbers.index.page_title') - if @sip_account.phone_numbers.count > 0 @@ -72,9 +82,20 @@ %br = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => PhoneNumber } +- if @sip_account.call_forwards.count > 0 || can?(:create, @sip_account.call_forwards.build) + %h2= t('call_forwards.index.page_title') + - if @sip_account.call_forwards.count > 0 + = render "call_forwards/index_core", :call_forwards => @sip_account.call_forwards + %br + = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => CallForward } + - if @sip_account.softkeys.count > 0 || can?(:create, @sip_account.softkeys.build) %h2= t("softkeys.index.page_title") - if @sip_account.softkeys.count > 0 = render "softkeys/index_core", :softkeys => @sip_account.softkeys %br - = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => Softkey }
\ No newline at end of file + = render :partial => 'shared/create_link', :locals => { :parent => @sip_account, :child_class => Softkey } + +- if @sip_account.calls.count > 0 + %h2= t("calls.index.page_title") + = render "calls/index_core", :calls => @sip_account.calls, :parent => @sip_account diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 0f6cc2c..8148005 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -29,22 +29,30 @@ = render :partial => 'shared/show_edit_destroy_part', :locals => { :parent => @tenant, :child => @user } - @user.sip_accounts.each do |sip_account| - - phone_number = sip_account.phone_numbers.order(:number).last - - if phone_number && !phone_number.number.blank? && phone_number.number[0] != '+' - %p - %strong= sip_account.phone_numbers.order(:number).last.number + - phone_numbers = sip_account.phone_numbers.order(:position) + %p + - if phone_numbers[0] + %strong= phone_numbers[0].number + - else + %strong= sip_account.to_s + - if phone_numbers[1] + %strong= phone_numbers[1].number + - if phone_numbers[2] + %strong= phone_numbers[2].number + - if phone_numbers[3] + %strong ... %p =link_to t("call_histories.index.page_title"), sip_account_call_histories_path(sip_account) %br =link_to t("voicemail_messages.index.page_title"), sip_account_voicemail_messages_path(sip_account) %br - =link_to t("call_forwards.index.page_title"), phone_number_call_forwards_path(phone_number) + =link_to t("call_forwards.index.page_title"), sip_account_call_forwards_path(sip_account) %br =link_to t("voicemail_settings.index.page_title"), sip_account_voicemail_settings_path(sip_account) %br =link_to t("softkeys.index.page_title"), sip_account_softkeys_path(sip_account) %br - =link_to t("ringtones.show.page_title"), phone_number_ringtones_path(phone_number) + =link_to t("ringtones.show.page_title"), sip_account_ringtones_path(sip_account) - if @user.conferences.any? %p diff --git a/config/backup.rb b/config/backup.rb index e5816c1..b50f7a8 100644 --- a/config/backup.rb +++ b/config/backup.rb @@ -24,14 +24,31 @@ Backup::Model.new(:GS5, 'GS5 backup') do db.host = "localhost" db.port = 3306 db.socket = "/var/run/mysqld/mysqld.sock" + db.skip_tables = ["backup_jobs", "restore_jobs", "fax_thumbnails"] end ## # Faxes # - if File.exists?('/opt/gemeinschaft/public/uploads/fax_document') + if File.exists?('/var/opt/gemeinschaft/fax') archive :faxes do |archive| - archive.add '/opt/gemeinschaft/public/uploads/fax_document' + # Incoming faxes + # + Dir.glob("/var/opt/gemeinschaft/fax/in/**/*.pdf").each do |fax_file| + archive.add(fax_file) + end + Dir.glob("/var/opt/gemeinschaft/fax/in/**/*.tiff").each do |fax_file| + archive.add(fax_file) + end + + # Outgoing faxes + # + Dir.glob("/var/opt/gemeinschaft/fax/out/**/*.pdf").each do |fax_file| + archive.add(fax_file) + end + Dir.glob("/var/opt/gemeinschaft/fax/out/**/*.tiff").each do |fax_file| + archive.add(fax_file) + end end end @@ -55,6 +72,4 @@ Backup::Model.new(:GS5, 'GS5 backup') do # Gzip [Compressor] # compress_with Gzip - -end - +end
\ No newline at end of file diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb index 062f823..06dc271 100644 --- a/config/initializers/simple_form.rb +++ b/config/initializers/simple_form.rb @@ -145,6 +145,7 @@ SimpleForm.setup do |config| # How the label text should be generated altogether with the required text. # config.label_text = lambda { |label, required| "#{required} #{label}" } + config.label_text = lambda { |label, required| "#{label}" } # You can define the class to use on all labels. Default is nil. config.label_class = 'control-label' diff --git a/config/locales/views/call_forwards/de.yml b/config/locales/views/call_forwards/de.yml index 3930938..4f6ee86 100644 --- a/config/locales/views/call_forwards/de.yml +++ b/config/locales/views/call_forwards/de.yml @@ -7,8 +7,8 @@ de: successfuly_destroyed: 'Die Rufumleitung wurde gelöscht.' index: page_title: 'Rufumleitungen' - phone_number_id: 'Telefonnummer' - call_forward_case_id: 'Art der Rufumleitung' + call_forwardable: 'Umleitendes Objekt' + call_forward_case: 'Art der Rufumleitung' timeout: 'Zeitüberschreitung' destination: 'Ziel' hunt_group: 'Rufgruppen-Verknüpfung' @@ -25,8 +25,8 @@ de: create_for: 'Neue Rufumleitung für die %{resource} anlegen' show: page_title: 'Rufumleitung anzeigen' - phone_number_id: 'Telefonnummer' - call_forward_case_id: 'Art der Rufumleitung' + call_forwardable: 'Umleitendes Objekt' + call_forward_case: 'Art der Rufumleitung' timeout: 'Zeitüberschreitung' destination: 'Ziel' hunt_group: 'Rufgruppen-Verknüpfung' @@ -44,10 +44,10 @@ de: edit: page_title: 'Rufumleitung bearbeiten' form: - phone_number_id: - label: 'Telefonnummer' + call_forwardable: + label: 'Umleitendes Objekt' hint: '' - call_forward_case_id: + call_forward_case: label: 'Art der Rufumleitung' hint: '' timeout: diff --git a/config/locales/views/call_forwards/en.yml b/config/locales/views/call_forwards/en.yml index 20fb834..65ae6b0 100644 --- a/config/locales/views/call_forwards/en.yml +++ b/config/locales/views/call_forwards/en.yml @@ -7,8 +7,8 @@ en: successfuly_destroyed: 'Successfully destroyed call forward.' index: page_title: 'Call forwards' - phone_number_id: 'Phone number' - call_forward_case_id: 'Call forward case' + call_forwardable: 'Forwarding entity' + call_forward_case: 'Call forward case' timeout: 'Timeout' destination: 'Destination' to_voicemail: 'Voicemail' @@ -25,8 +25,8 @@ en: create_for: 'New call forward for phone number %{resource}' show: page_title: 'Show call forward' - phone_number_id: 'Phone number' - call_forward_case_id: 'Call forward case' + call_forwardable: 'Forwarding entity' + call_forward_case: 'Call forward case' timeout: 'Timeout' destination: 'Destination' hunt_group: 'Hunt group connection' @@ -44,10 +44,10 @@ en: edit: page_title: 'Editing call forward' form: - phone_number_id: - label: 'Phone number' + call_forwardable: + label: 'Forwarding entity' hint: '' - call_forward_case_id: + call_forward_case: label: 'Call forward case' hint: '' timeout: diff --git a/config/locales/views/calls/de.yml b/config/locales/views/calls/de.yml new file mode 100644 index 0000000..1410e34 --- /dev/null +++ b/config/locales/views/calls/de.yml @@ -0,0 +1,37 @@ +de: + calls: + name: 'Anruf' + controller: + successfuly_created: 'Einen neue Anruf wurde erstellt.' + successfuly_updated: 'Der Anruf wurde aktualisiert.' + successfuly_destroyed: 'Der Anruf wurde aufgelegt.' + index: + page_title: 'Anrufe' + uuid: 'UUID' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie diese Anruf auflegen möchten?' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neuer Anruf' + create_for: 'Neuer Anruf für %{resource}' + show: + page_title: 'Anruf' + uuid: 'UUID' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie diese Anruf auflegen möchten?' + destroy: 'Auflegen' + edit: 'Bearbeiten' + view_all: 'Alle Anrufe anzeigen' + new: + page_title: 'Neuer Anruf' + edit: + page_title: 'Anruf bearbeiten' + form: + uuid: + label: 'UUID' + hint: '' + destination: + label: 'Ziel' + hint: '' + submit: 'Absenden' diff --git a/config/locales/views/calls/en.yml b/config/locales/views/calls/en.yml new file mode 100644 index 0000000..9161d03 --- /dev/null +++ b/config/locales/views/calls/en.yml @@ -0,0 +1,37 @@ +en: + calls: + name: 'Call' + controller: + successfuly_created: 'Successfully created call.' + successfuly_updated: 'Successfully updated call.' + successfuly_destroyed: 'Successfully hung up call.' + index: + page_title: 'Calls' + uuid: 'UUID' + actions: + confirm_destroy: 'Are you sure you want to drop this call?' + destroy: 'Hang up' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New call for sip account %{resource}' + show: + page_title: 'Call' + uuid: 'UUID' + actions: + confirm_destroy: 'Are you sure you want to drop this call?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View all calls' + new: + page_title: 'New call' + edit: + page_title: 'Editing call' + form: + uuid: + label: 'UUID' + hint: '' + destination: + label: 'Destination' + hint: '' + submit: 'Submit' diff --git a/config/locales/views/fax_accounts/de.yml b/config/locales/views/fax_accounts/de.yml index cc93a24..8e6f954 100644 --- a/config/locales/views/fax_accounts/de.yml +++ b/config/locales/views/fax_accounts/de.yml @@ -1,12 +1,12 @@ de: fax_accounts: - name: 'Software-Fax-Konto' + name: 'Software-Fax' controller: - successfuly_created: 'Eine neues Software-Fax-Konto wurde erstellt.' - successfuly_updated: 'Das Software-Fax-Konto wurde aktualisiert.' - successfuly_destroyed: 'Das Software-Fax-Konto wurde gelöscht.' + successfuly_created: 'Eine neues Software-Fax wurde erstellt.' + successfuly_updated: 'Das Software-Fax wurde aktualisiert.' + successfuly_destroyed: 'Das Software-Fax wurde gelöscht.' index: - page_title: 'Software-Fax-Konten' + page_title: 'Software-Faxe' name: 'Name' station_id: 'Stations-ID' email: 'E-Mail' @@ -17,30 +17,30 @@ de: sent: 'Gesendet' retries: 'Max. Anzahl von Sendeversuchen' last_update: 'Letzter Eintrag' - send_a_fax: 'Fax versenden' + send_a_fax: 'versenden' actions: - confirm_destroy: 'Sind Sie sicher, dass Sie dieses Software-Fax-Konto löschen möchten?' + confirm_destroy: 'Sind Sie sicher, dass Sie dieses Software-Fax löschen möchten?' destroy: 'Löschen' edit: 'Bearbeiten' show: 'Anzeigen' create: 'Neu anlegen' create_for: 'Neues Fax-Konto für %{resource} anlegen' show: - page_title: 'Software-Fax-Konto anzeigen' + page_title: 'Software-Fax anzeigen' name: 'Name' station_id: 'Stations-ID' email: 'E-Mail' days_till_auto_delete: 'Anzahl der Tage bis Faxe gelöscht werden' retries: 'Max. Anzahl von Sendeversuchen' actions: - confirm_destroy: 'Sind Sie sicher, dass Sie dieses Software-Fax-Konto löschen möchten?' + confirm_destroy: 'Sind Sie sicher, dass Sie dieses Software-Fax löschen möchten?' destroy: 'Löschen' edit: 'Bearbeiten' view_all: 'Alle anzeigen' new: - page_title: 'Neues Software-Fax-Konto' + page_title: 'Neues Software-Fax' edit: - page_title: 'Software-Fax-Konto bearbeiten' + page_title: 'Software-Fax bearbeiten' form: name: label: 'Name' diff --git a/config/locales/views/fax_documents/de.yml b/config/locales/views/fax_documents/de.yml index 6bfa86b..da59833 100644 --- a/config/locales/views/fax_documents/de.yml +++ b/config/locales/views/fax_documents/de.yml @@ -62,7 +62,7 @@ de: transmission_time: 'Übertragungszeit' sent_at: 'Sendezeit' document_total_pages: 'Seitenanzahl' - document_transferred_pages: 'Übertragende Seiten' + document_transferred_pages: 'Übertragene Seiten' ecm_requested: 'Fehlerkorrektur (ECM) angefragt' ecm_used: 'Fehlerkorrektur (ECM) verwendet' image_resolution: 'Bildauflösung' diff --git a/config/locales/views/gemeinschaft_setups/de.yml b/config/locales/views/gemeinschaft_setups/de.yml index eb0145c..c035c96 100644 --- a/config/locales/views/gemeinschaft_setups/de.yml +++ b/config/locales/views/gemeinschaft_setups/de.yml @@ -27,7 +27,7 @@ de: hint: '' default_area_code: label: 'Standard Ortsvorwahl' - hint: '030 für Berlin, 0261 für Koblenz, 02631 für Neuwied, usw.' + hint: 'ohne führende Null; z.B. 30 für Berlin, 261 für Koblenz, 2631 für Neuwied, usw.' trunk_access_code: label: 'Amtsholungsziffer' hint: '' diff --git a/config/locales/views/gemeinschaft_setups/en.yml b/config/locales/views/gemeinschaft_setups/en.yml index 3a1ac39..15edca5 100644 --- a/config/locales/views/gemeinschaft_setups/en.yml +++ b/config/locales/views/gemeinschaft_setups/en.yml @@ -11,7 +11,7 @@ en: user_group_name: 'Users' super_admin_group_name: 'Super-Admins' new: - page_title: 'New Gemeinschaft setup' + page_title: 'Gemeinschaft Setup' form: user_id: label: 'User' diff --git a/config/locales/views/group_memberships/de.yml b/config/locales/views/group_memberships/de.yml new file mode 100644 index 0000000..7fdc100 --- /dev/null +++ b/config/locales/views/group_memberships/de.yml @@ -0,0 +1,50 @@ +de: + group_memberships: + name: 'Groupmembership' + controller: + successfuly_created: 'Groupmembership wurde angelegt.' + successfuly_updated: 'Groupmembership wurde aktualisiert.' + successfuly_destroyed: 'Groupmembership wurde gelöscht.' + index: + page_title: 'Übersicht von Groupmembership' + group_id: 'Group' + item_type: 'Item type' + item_id: 'Item' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Groupmembership' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Groupmembership neu anlegen für %{resource}' + show: + page_title: 'Groupmembership bearbeiten' + group_id: 'Group' + item_type: 'Item type' + item_id: 'Item' + 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: 'Groupmembership neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Groupmembership bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + group_id: + label: 'Group' + hint: '' + item_type: + label: 'Item type' + hint: '' + item_id: + label: 'Item' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/group_memberships/en.yml b/config/locales/views/group_memberships/en.yml new file mode 100644 index 0000000..35740a3 --- /dev/null +++ b/config/locales/views/group_memberships/en.yml @@ -0,0 +1,50 @@ +en: + group_memberships: + name: 'Groupmembership' + controller: + successfuly_created: 'Successfully created Groupmembership.' + successfuly_updated: 'Successfully updated Groupmembership.' + successfuly_destroyed: 'Successfully destroyed Groupmembership.' + index: + page_title: 'Listing Groupmembership' + group_id: 'Group' + item_type: 'Item type' + item_id: 'Item' + actions: + confirm_destroy: 'Are you sure you want to delete this Groupmembership?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Groupmembership for %{resource}' + show: + page_title: 'Show Groupmembership' + group_id: 'Group' + item_type: 'Item type' + item_id: 'Item' + actions: + confirm_destroy: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New Groupmembership' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Groupmembership' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + group_id: + label: 'Group' + hint: '' + item_type: + label: 'Item type' + hint: '' + item_id: + label: 'Item' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/group_permissions/de.yml b/config/locales/views/group_permissions/de.yml new file mode 100644 index 0000000..c075830 --- /dev/null +++ b/config/locales/views/group_permissions/de.yml @@ -0,0 +1,50 @@ +de: + group_permissions: + name: 'Grouppermission' + controller: + successfuly_created: 'Grouppermission wurde angelegt.' + successfuly_updated: 'Grouppermission wurde aktualisiert.' + successfuly_destroyed: 'Grouppermission wurde gelöscht.' + index: + page_title: 'Übersicht von Grouppermission' + group_id: 'Group' + permission: 'Permission' + target_group_id: 'Target group' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Grouppermission' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Grouppermission neu anlegen für %{resource}' + show: + page_title: 'Grouppermission bearbeiten' + group_id: 'Group' + permission: 'Permission' + target_group_id: 'Target group' + 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: 'Grouppermission neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Grouppermission bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + group_id: + label: 'Group' + hint: '' + permission: + label: 'Permission' + hint: '' + target_group_id: + label: 'Target group' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/group_permissions/en.yml b/config/locales/views/group_permissions/en.yml new file mode 100644 index 0000000..2a5f48e --- /dev/null +++ b/config/locales/views/group_permissions/en.yml @@ -0,0 +1,50 @@ +en: + group_permissions: + name: 'Grouppermission' + controller: + successfuly_created: 'Successfully created Grouppermission.' + successfuly_updated: 'Successfully updated Grouppermission.' + successfuly_destroyed: 'Successfully destroyed Grouppermission.' + index: + page_title: 'Listing Grouppermission' + group_id: 'Group' + permission: 'Permission' + target_group_id: 'Target group' + actions: + confirm_destroy: 'Are you sure you want to delete this Grouppermission?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Grouppermission for %{resource}' + show: + page_title: 'Show Grouppermission' + group_id: 'Group' + permission: 'Permission' + target_group_id: 'Target group' + actions: + confirm_destroy: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'New Grouppermission' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Grouppermission' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + group_id: + label: 'Group' + hint: '' + permission: + label: 'Permission' + hint: '' + target_group_id: + label: 'Target group' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/groups/de.yml b/config/locales/views/groups/de.yml new file mode 100644 index 0000000..fc60a72 --- /dev/null +++ b/config/locales/views/groups/de.yml @@ -0,0 +1,50 @@ +de: + groups: + name: 'Group' + controller: + successfuly_created: 'Group wurde angelegt.' + successfuly_updated: 'Group wurde aktualisiert.' + successfuly_destroyed: 'Group wurde gelöscht.' + index: + page_title: 'Übersicht von Group' + name: 'Name' + active: 'Active' + comment: 'Comment' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Group' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Group neu anlegen für %{resource}' + show: + page_title: 'Group bearbeiten' + name: 'Name' + active: 'Active' + 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: 'Group neu anlegen' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Group bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + name: + label: 'Name' + hint: '' + active: + label: 'Active' + hint: '' + comment: + label: 'Comment' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/groups/en.yml b/config/locales/views/groups/en.yml new file mode 100644 index 0000000..a7fb666 --- /dev/null +++ b/config/locales/views/groups/en.yml @@ -0,0 +1,50 @@ +en: + groups: + name: 'Group' + controller: + successfuly_created: 'Successfully created Group.' + successfuly_updated: 'Successfully updated Group.' + successfuly_destroyed: 'Successfully destroyed Group.' + index: + page_title: 'Listing Group' + name: 'Name' + active: 'Active' + comment: 'Comment' + actions: + confirm_destroy: 'Are you sure you want to delete this Group?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Group for %{resource}' + show: + page_title: 'Show Group' + name: 'Name' + active: 'Active' + 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 Group' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Group' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + name: + label: 'Name' + hint: '' + active: + label: 'Active' + hint: '' + comment: + label: 'Comment' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/phone_book_entries/de.yml b/config/locales/views/phone_book_entries/de.yml index 2c77aa5..bdd0d67 100644 --- a/config/locales/views/phone_book_entries/de.yml +++ b/config/locales/views/phone_book_entries/de.yml @@ -6,7 +6,7 @@ de: successfuly_updated: 'Der Telefonbucheintrag "%{resource}" wurde aktualisiert.' successfuly_destroyed: 'Der Telefonbucheintrag wurde gelöscht.' index: - page_title: 'Anzahl Telefonbucheinträge' + page_title: 'Telefonbucheinträge' phone_book_id: 'Telefonbuch' first_name: 'Vorname' middle_name: 'Zweiter Vorname' diff --git a/config/locales/views/phone_books/de.yml b/config/locales/views/phone_books/de.yml index fa93945..c7ba5c7 100644 --- a/config/locales/views/phone_books/de.yml +++ b/config/locales/views/phone_books/de.yml @@ -5,7 +5,7 @@ de: name: 'Firmentelefonbuch' description: 'Ein für alle Benutzer von %{resource} lesbares Telefonbuch.' private_phone_book: - name: 'Privates Telefonbuch von %{resource}' + name: 'Privates Telefonbuch' description: 'Ein privates Telefonbuch.' controller: successfuly_created: 'Ein neues Telefonbuch wurde erstellt.' diff --git a/config/locales/views/restore_jobs/de.yml b/config/locales/views/restore_jobs/de.yml new file mode 100644 index 0000000..3fdd72c --- /dev/null +++ b/config/locales/views/restore_jobs/de.yml @@ -0,0 +1,45 @@ +de: + restore_jobs: + name: 'Restore Auftrag' + controller: + successfuly_created: 'Restore Auftrag wurde angelegt.' + successfuly_updated: 'Restore Auftrag wurde aktualisiert.' + successfuly_destroyed: 'Restore Auftrag wurde gelöscht.' + index: + page_title: 'Liste Restore Aufträge' + state: 'Status' + backup_file: 'Backup Datei' + actions: + confirm_destroy: 'Sind Sie sicher, dass Sie folgendes löschen möchten: Restore Auftrag' + destroy: 'Löschen' + edit: 'Bearbeiten' + show: 'Anzeigen' + create: 'Neu anlegen' + create_for: 'Restore Auftrag neu anlegen für %{resource}' + show: + page_title: 'Restore Auftrag bearbeiten' + state: 'Status' + backup_file: 'Backup Datei' + 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: 'Restore von einem Backup' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: + page_title: 'Restore Auftrag bearbeiten' + actions: + back_to_list: 'Zurück zur Übersicht' + edit: 'Bearbeiten' + view_all: 'Alle anzeigen' + form: + state: + label: 'Status' + hint: '' + backup_file: + label: 'Backup Datei' + hint: '' + submit: 'Absenden'
\ No newline at end of file diff --git a/config/locales/views/restore_jobs/en.yml b/config/locales/views/restore_jobs/en.yml new file mode 100644 index 0000000..636c335 --- /dev/null +++ b/config/locales/views/restore_jobs/en.yml @@ -0,0 +1,45 @@ +en: + restore_jobs: + name: 'Restorejob' + controller: + successfuly_created: 'Successfully created Restorejob.' + successfuly_updated: 'Successfully updated Restorejob.' + successfuly_destroyed: 'Successfully destroyed Restorejob.' + index: + page_title: 'Listing Restorejob' + state: 'State' + backup_file: 'Backup file' + actions: + confirm_destroy: 'Are you sure you want to delete this Restorejob?' + destroy: 'Delete' + edit: 'Edit' + show: 'View' + create: 'New' + create_for: 'New Restorejob for %{resource}' + show: + page_title: 'Show Restorejob' + state: 'State' + backup_file: 'Backup file' + actions: + confirm_destroy: 'Are you sure you want to delete this element?' + destroy: 'Delete' + edit: 'Edit' + view_all: 'View All' + new: + page_title: 'Restore from a backup' + actions: + back_to_list: 'Back to Index' + edit: + page_title: 'Editing Restorejob' + actions: + back_to_list: 'Back to Index' + edit: 'Edit' + view_all: 'View All' + form: + state: + label: 'State' + hint: '' + backup_file: + label: 'Backup file' + hint: '' + submit: 'Submit'
\ No newline at end of file diff --git a/config/locales/views/sip_accounts/de.yml b/config/locales/views/sip_accounts/de.yml index 7a7e540..2b4939b 100644 --- a/config/locales/views/sip_accounts/de.yml +++ b/config/locales/views/sip_accounts/de.yml @@ -41,6 +41,8 @@ de: registration: 'Registrierung' expires: 'Läuft ab' user_agent: 'User Agent' + tel_protocol: 'TEL Protokoll' + register_tel_protocol: 'Für tel: URLs registrieren' actions: confirm_destroy: 'Sind Sie sicher, dass Sie diesen SIP-Account löschen möchten?' destroy: 'Löschen' diff --git a/config/locales/views/sip_accounts/en.yml b/config/locales/views/sip_accounts/en.yml index 35d5456..78d20c2 100644 --- a/config/locales/views/sip_accounts/en.yml +++ b/config/locales/views/sip_accounts/en.yml @@ -41,6 +41,8 @@ en: registration: 'Registration' expires: 'Expires' user_agent: 'User Agent' + tel_protocol: 'TEL Protocol' + register_tel_protocol: 'Register for tel: URLs with browser' actions: confirm_destroy: 'Are you sure you want to delete this SIP account?' destroy: 'Delete' diff --git a/config/routes.rb b/config/routes.rb index 65a9ac2..2fe1682 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,12 @@ Gemeinschaft42c::Application.routes.draw do + resources :restore_jobs + + resources :groups do + resources :group_memberships + resources :group_permissions + end + resources :sim_card_providers do resources :sim_cards, :except => [:edit, :update] end @@ -248,6 +255,9 @@ Gemeinschaft42c::Application.routes.draw do resources :phones_sip_accounts resources :phone_numbers resources :softkeys + resources :call_forwards + resources :ringtones + resources :calls resources :call_histories do collection do delete 'destroy_multiple' @@ -267,6 +277,9 @@ Gemeinschaft42c::Application.routes.draw do end end resources :voicemail_settings + member do + get 'call' + end end resources :phones, :only => [] do diff --git a/config/schedule.rb b/config/schedule.rb index 94603f1..f2c1a09 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -7,7 +7,7 @@ end # Auto-Reboot of Phones which should be rebootet # every 1.day, :at => '2:30 am' do - command "/opt/GS5/script/logout_phones.sh" + command "/opt/GS5/script/logout_phones" end # Learn more: http://github.com/javan/whenever diff --git a/db/migrate/20130109090000_populate_gs_parameter_with_dialplan_defaults.rb b/db/migrate/20130109090000_populate_gs_parameter_with_dialplan_defaults.rb index fe1cdae..a8350a3 100644 --- a/db/migrate/20130109090000_populate_gs_parameter_with_dialplan_defaults.rb +++ b/db/migrate/20130109090000_populate_gs_parameter_with_dialplan_defaults.rb @@ -79,7 +79,7 @@ class PopulateGsParameterWithDialplanDefaults < ActiveRecord::Migration GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'rate', :value => 16000, :class_type => 'Integer') GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'interval', :value => 20, :class_type => 'Integer') GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'energy-level', :value => 300, :class_type => 'Integer') - GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'sound-prefix', :value => '/opt/freeswitch/sounds/en/us/callie', :class_type => 'String') + GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'sound-prefix', :value => '/opt/freeswitch/sounds/de/tts/google', :class_type => 'String') GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'muted-sound', :value => 'conference/conf-muted.wav', :class_type => 'String') GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'unmuted-sound', :value => 'conference/conf-unmuted.wav', :class_type => 'String') GsParameter.create(:entity => 'conferences', :section => 'parameters', :name => 'alone-sound', :value => 'conference/conf-alone.wav', :class_type => 'String') @@ -101,7 +101,7 @@ class PopulateGsParameterWithDialplanDefaults < ActiveRecord::Migration GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'dial_timeout', :value => '120', :class_type => 'Integer') GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'max_loops', :value => '20', :class_type => 'Integer') GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'default_ringtone', :value => '1', :class_type => 'Integer') - GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'default_language', :value => 'en', :class_type => 'String') + GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'default_language', :value => 'de', :class_type => 'String') GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'phone_book_entry_image_url', :value => 'http://192.168.0.150/uploads/phone_book_entry/image', :class_type => 'String') GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'user_image_url', :value => 'http://192.168.0.150/uploads/user/image', :class_type => 'String') GsParameter.create(:entity => 'dialplan', :section => 'parameters', :name => 'ringtone_url', :value => 'http://192.168.0.150', :class_type => 'String') diff --git a/db/migrate/20130213110000_add_sounds_to_parameters.rb b/db/migrate/20130213110000_add_sounds_to_parameters.rb index 8c4cd94..dd20ca3 100644 --- a/db/migrate/20130213110000_add_sounds_to_parameters.rb +++ b/db/migrate/20130213110000_add_sounds_to_parameters.rb @@ -1,7 +1,7 @@ class AddSoundsToParameters < ActiveRecord::Migration def up GsParameter.create(:entity => 'dialplan', :section => 'sounds', :name => 'en', :value => '/opt/freeswitch/sounds/en/us/callie', :class_type => 'String') - GsParameter.create(:entity => 'dialplan', :section => 'sounds', :name => 'de', :value => '/opt/freeswitch/sounds/de/de/callie', :class_type => 'String') + GsParameter.create(:entity => 'dialplan', :section => 'sounds', :name => 'de', :value => '/opt/freeswitch/sounds/de/tts/google', :class_type => 'String') end def down diff --git a/db/migrate/20130219135000_remove_sound_prefix_from_conference_parameters.rb b/db/migrate/20130219135000_remove_sound_prefix_from_conference_parameters.rb new file mode 100644 index 0000000..950e3af --- /dev/null +++ b/db/migrate/20130219135000_remove_sound_prefix_from_conference_parameters.rb @@ -0,0 +1,8 @@ +class RemoveSoundPrefixFromConferenceParameters < ActiveRecord::Migration + def up + GsParameter.where(:entity => 'conferences', :section => 'parameters', :name => 'sound-prefix').destroy_all + end + + def down + end +end diff --git a/db/migrate/20130222074610_create_groups.rb b/db/migrate/20130222074610_create_groups.rb new file mode 100644 index 0000000..e5848b9 --- /dev/null +++ b/db/migrate/20130222074610_create_groups.rb @@ -0,0 +1,14 @@ +class CreateGroups < ActiveRecord::Migration + def self.up + create_table :groups do |t| + t.string :name + t.boolean :active + t.string :comment + t.timestamps + end + end + + def self.down + drop_table :groups + end +end diff --git a/db/migrate/20130222074652_create_group_memberships.rb b/db/migrate/20130222074652_create_group_memberships.rb new file mode 100644 index 0000000..e572445 --- /dev/null +++ b/db/migrate/20130222074652_create_group_memberships.rb @@ -0,0 +1,14 @@ +class CreateGroupMemberships < ActiveRecord::Migration + def self.up + create_table :group_memberships do |t| + t.integer :group_id + t.string :item_type + t.integer :item_id + t.timestamps + end + end + + def self.down + drop_table :group_memberships + end +end diff --git a/db/migrate/20130222092313_create_group_permissions.rb b/db/migrate/20130222092313_create_group_permissions.rb new file mode 100644 index 0000000..5949819 --- /dev/null +++ b/db/migrate/20130222092313_create_group_permissions.rb @@ -0,0 +1,14 @@ +class CreateGroupPermissions < ActiveRecord::Migration + def self.up + create_table :group_permissions do |t| + t.integer :group_id + t.string :permission + t.integer :target_group_id + t.timestamps + end + end + + def self.down + drop_table :group_permissions + end +end diff --git a/db/migrate/20130224081700_groups_to_user_groups_in_routes.rb b/db/migrate/20130224081700_groups_to_user_groups_in_routes.rb new file mode 100644 index 0000000..5e03cfa --- /dev/null +++ b/db/migrate/20130224081700_groups_to_user_groups_in_routes.rb @@ -0,0 +1,19 @@ +class GroupsToUserGroupsInRoutes < ActiveRecord::Migration + def up + RouteElement.where(:var_in => 'val:auth_account.owner.groups').each do |route_element| + route_element.update_attributes(:var_in => 'val:auth_account.owner.user_groups') + end + RouteElement.where(:var_in => 'val:account.owner.groups').each do |route_element| + route_element.update_attributes(:var_in => 'val:account.owner.user_groups') + end + end + + def down + RouteElement.where(:var_in => 'val:auth_account.owner.user_groups').each do |route_element| + route_element.update_attributes(:var_in => 'val:auth_account.owner.groups') + end + RouteElement.where(:var_in => 'val:account.owner.user_groups').each do |route_element| + route_element.update_attributes(:var_in => 'val:account.owner.groups') + end + end +end diff --git a/db/migrate/20130224091700_add_initial_groups.rb b/db/migrate/20130224091700_add_initial_groups.rb new file mode 100644 index 0000000..f680fb6 --- /dev/null +++ b/db/migrate/20130224091700_add_initial_groups.rb @@ -0,0 +1,22 @@ +class AddInitialGroups < ActiveRecord::Migration + def up + Group.create(:name => 'admins', :active => true, :comment => 'Administrator user accounts') + Group.create(:name => 'users', :active => true, :comment => 'Generic user accounts') + Group.create(:name => 'tenant_sip_accounts', :active => true, :comment => 'SIP accounts owned by tenants') + + user_sip_accounts = Group.create(:name => 'user_sip_accounts', :active => true, :comment => 'SIP accounts owned by user accounts') + user_sip_accounts.group_permissions.create(:permission => 'pickup', :target_group_id => user_sip_accounts.id) + + Group.create(:name => 'international_calls', :active => true, :comment => 'International calls permitted') + Group.create(:name => 'national_calls', :active => true, :comment => 'National calls permitted') + + GsParameter.create(:entity => 'group', :section => 'default', :name => 'User.admin', :value => '--- [admins]\n', :class_type => 'YAML') + GsParameter.create(:entity => 'group', :section => 'default', :name => 'User', :value => '--- [users]\n', :class_type => 'YAML') + GsParameter.create(:entity => 'group', :section => 'default', :name => 'SipAccount.user', :value => '--- [user_sip_accounts, international_calls, national_calls]\n', :class_type => 'YAML') + GsParameter.create(:entity => 'group', :section => 'default', :name => 'SipAccount.tenant', :value => '--- [tenant_sip_accounts]\n', :class_type => 'YAML') + end + + def down + Group.destroy_all + end +end diff --git a/db/migrate/20130225091200_add_destinationable_to_call_forward.rb b/db/migrate/20130225091200_add_destinationable_to_call_forward.rb new file mode 100644 index 0000000..89e4b3b --- /dev/null +++ b/db/migrate/20130225091200_add_destinationable_to_call_forward.rb @@ -0,0 +1,21 @@ +class AddDestinationableToCallForward < ActiveRecord::Migration + def up + add_column :call_forwards, :destinationable_type, :string + add_column :call_forwards, :destinationable_id, :integer + + CallForward.all.each do |call_forward| + call_forward.update_attributes(:destinationable_type => call_forward.call_forwardable_type, :destinationable_id => call_forward.call_forwardable_id, :call_forwardable_type => 'PhoneNumber', :call_forwardable_id => call_forward.phone_number_id ) + end + + remove_column :call_forwards, :phone_number_id + end + + def down + add_column :call_forwards, :phone_number_id, :integer + CallForward.where(:call_forwardable_type => 'PhoneNumber').each do |call_forward| + call_forward.update_attributes(:phone_number_id => call_forward.call_forwardable_id, :call_forwardable_type => call_forward.destinationable_type, :call_forwardable_id => call_forward.destinationable_id) + end + remove_column :call_forwards, :destinationable_type + remove_column :call_forwards, :destinationable_id + end +end diff --git a/db/migrate/20130225160423_create_restore_jobs.rb b/db/migrate/20130225160423_create_restore_jobs.rb new file mode 100644 index 0000000..9f83791 --- /dev/null +++ b/db/migrate/20130225160423_create_restore_jobs.rb @@ -0,0 +1,13 @@ +class CreateRestoreJobs < ActiveRecord::Migration + def self.up + create_table :restore_jobs do |t| + t.string :state + t.string :backup_file + t.timestamps + end + end + + def self.down + drop_table :restore_jobs + end +end diff --git a/db/schema.rb b/db/schema.rb index df55604..60bc7f5 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 => 20130215133749) do +ActiveRecord::Schema.define(:version => 20130225160423) do create_table "access_authorizations", :force => true do |t| t.string "access_authorizationable_type" @@ -554,6 +554,30 @@ ActiveRecord::Schema.define(:version => 20130215133749) do t.string "trunk_access_code" end + create_table "group_memberships", :force => true do |t| + t.integer "group_id" + t.string "item_type" + t.integer "item_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "group_permissions", :force => true do |t| + t.integer "group_id" + t.string "permission" + t.integer "target_group_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "groups", :force => true do |t| + t.string "name" + t.boolean "active" + t.string "comment" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "gs_cluster_sync_log_entries", :force => true do |t| t.integer "gs_node_id" t.string "class_name" @@ -854,6 +878,13 @@ ActiveRecord::Schema.define(:version => 20130215133749) do add_index "registrations", ["reg_user", "realm", "hostname"], :name => "regindex1" + create_table "restore_jobs", :force => true do |t| + t.string "state" + t.string "backup_file" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "ringtones", :force => true do |t| t.string "ringtoneable_type" t.integer "ringtoneable_id" diff --git a/lib/tasks/backup.rake b/lib/tasks/backup.rake index c285e1f..21b0fac 100644 --- a/lib/tasks/backup.rake +++ b/lib/tasks/backup.rake @@ -3,4 +3,56 @@ namespace :backup do task :daily_backup => :environment do # This would be the daily backup. end + + desc "Restore the system" + task :restore => :environment do + # This task takes the first RestoreJob to restore the system. + # + if RestoreJob.where(:state => 'new').any? + restore_job = RestoreJob.where(:state => 'new').order(:created_at).last + tmp_dir = "/tmp/gs5_restore_directory" + FileUtils.rm_rf tmp_dir + FileUtils.mkdir_p tmp_dir + system "cd #{tmp_dir} && sudo /bin/tar xzf #{restore_job.backup_file.path}" + restore_directory = Dir.glob("/tmp/gs5_restore_directory/*").first + system "cd #{restore_directory} && sudo /bin/tar xf GS5.tar && rm GS5.tar" + + # Restore faxes + # + system "cd / && sudo /bin/tar xzfP #{restore_directory}/GS5/archives/faxes.tar.gz" + + # Restore voicemails + # + system "cd / && sudo /bin/tar xzfP #{restore_directory}/GS5/archives/voicemails.tar.gz" + + # Delete the archive tar.gz to get more air to breathe + # + FileUtils.mkdir_p "#{restore_directory}/GS5/archives" + + # Restore the database + # + system_odbc_ini_file = '/var/lib/freeswitch/.odbc.ini' + system_odbc_configuration = IniFile.load(system_odbc_ini_file) + database = system_odbc_configuration['gemeinschaft']['DATABASE'] + db_user = system_odbc_configuration['gemeinschaft']['USER'] + db_password = system_odbc_configuration['gemeinschaft']['PASSWORD'] + + system "gunzip < #{restore_directory}/GS5/databases/MySQL/gemeinschaft.sql.gz | mysql -u #{db_user} -p#{db_password} #{database}" + + FileUtils.rm_rf tmp_dir + + system "cd /opt/gemeinschaft && rake db:migrate" + + # Rebuild the thumbnails + # + FaxDocument.all.each do |fax_document| + fax_document.render_thumbnails + end + + # Delete the restore_job. No need to waste that space. + # + restore_job.destroy + end + end + end
\ No newline at end of file diff --git a/lib/tasks/send_fax_notifications.rake b/lib/tasks/send_fax_notifications.rake index 2ac74c8..b456466 100644 --- a/lib/tasks/send_fax_notifications.rake +++ b/lib/tasks/send_fax_notifications.rake @@ -6,7 +6,7 @@ task :send_fax_notifications => :environment do FaxDocument.where(:state => 'received').each do |fax_document| TIFF_FUFFIX = ".tiff" PDF_SUFFIX = ".pdf" - TMP_DIR = "/tmp/" + TMP_DIR = "/var/spool/freeswitch/" tiff_file = File.basename(fax_document.tiff.to_s) diff --git a/misc/freeswitch/conf/freeswitch.xml b/misc/freeswitch/conf/freeswitch.xml index 4969b07..f72651f 100644 --- a/misc/freeswitch/conf/freeswitch.xml +++ b/misc/freeswitch/conf/freeswitch.xml @@ -27,6 +27,14 @@ </match> </input> </macro> + <macro name="voicemail_change_pass_success"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-password_has_been_changed.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> <macro name="voicemail_fail_auth"> <input pattern="(.*)"> <match> @@ -536,6 +544,14 @@ </match> </input> </macro> + <macro name="voicemail_change_pass_success"> + <input pattern="(.*)"> + <match> + <action function="play-file" data="voicemail/vm-password_has_been_changed.wav"/> + <action function="say" data="$1" method="pronounced" type="name_spelled"/> + </match> + </input> + </macro> <macro name="voicemail_fail_auth"> <input pattern="(.*)"> <match> diff --git a/misc/freeswitch/scripts/common/call_forwarding.lua b/misc/freeswitch/scripts/common/call_forwarding.lua index 400fcde..192c694 100644 --- a/misc/freeswitch/scripts/common/call_forwarding.lua +++ b/misc/freeswitch/scripts/common/call_forwarding.lua @@ -37,6 +37,61 @@ function CallForwarding.find_by_id(self, id) return nil end + +function CallForwarding.list_by_owner(self, call_forwardable_id, call_forwardable_type, caller_ids) + require 'common.str'; + + if not tonumber(call_forwardable_id) or common.str.blank(call_forwardable_type) then + return {}; + end + + local sql_query = 'SELECT \ + `a`.`destination` AS `number`, \ + `a`.`destinationable_id` AS `id`, \ + `a`.`destinationable_type` AS `type`, \ + `a`.`call_forwardable_id`, \ + `a`.`call_forwardable_type`, \ + `a`.`timeout`, `a`.`depth`, \ + `a`.`source`, \ + `b`.`value` AS `service` \ + FROM `call_forwards` `a` JOIN `call_forward_cases` `b` ON `a`.`call_forward_case_id` = `b`.`id` \ + WHERE `a`.`call_forwardable_id`= ' .. tonumber(call_forwardable_id) .. ' \ + AND `a`.`call_forwardable_type`= ' .. self.database:escape(call_forwardable_type, '"') .. ' \ + AND `a`.`active` IS TRUE'; + + local call_forwarding_entries = {}; + + self.database:query(sql_query, function(forwarding_entry) + local entry_match = false; + + if common.str.blank(forwarding_entry.source) then + entry_match = true; + else + local sources = common.str.strip_to_a(forwarding_entry.source, ',') + for source_index=1, #sources do + for caller_id_index=1, #caller_ids do + if caller_ids[caller_id_index]:match(sources[source_index]) then + entry_match = true; + self.log:debug('CALL_FORWARDING - source match: ', sources[source_index], ' ~ ', caller_ids[caller_id_index] ); + break; + end + end + end + end + + if entry_match then + call_forwarding_entries[forwarding_entry.service] = forwarding_entry; + self.log:debug('CALL_FORWARDING - ', call_forwardable_type, '=', call_forwardable_id, + ', service: ', forwarding_entry.service, + ', destination: ',forwarding_entry.type, '=', forwarding_entry.id, + ', number: ', forwarding_entry.number); + end + end) + + return call_forwarding_entries; +end + + function CallForwarding.presence_set(self, presence_state) require 'dialplan.presence' local presence = dialplan.presence.Presence:new(); diff --git a/misc/freeswitch/scripts/common/conference.lua b/misc/freeswitch/scripts/common/conference.lua index f6a4d87..b56cba9 100644 --- a/misc/freeswitch/scripts/common/conference.lua +++ b/misc/freeswitch/scripts/common/conference.lua @@ -159,7 +159,7 @@ function Conference.enter(self, caller, domain) caller:sleep(1000); caller.session:sayPhrase('conference_welcome'); - if pin and pin ~= "" then + if not common.str.blank(pin) then local digits = ""; for i = 1, 3, 1 do if digits == pin then @@ -167,7 +167,7 @@ function Conference.enter(self, caller, domain) elseif digits ~= "" then caller.session:sayPhrase('conference_bad_pin'); end - digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-enter_conf_pin.wav', PIN_TIMEOUT, '#'); + digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-pin.wav', PIN_TIMEOUT, '#'); end if digits ~= pin then caller.session:sayPhrase('conference_goodbye'); @@ -191,7 +191,7 @@ function Conference.enter(self, caller, domain) -- Record caller's name if common.str.to_b(self.record.announce_new_member_by_name) or common.str.to_b(self.record.announce_left_member_by_name) then local uid = session:get_uuid(); - name_file = "/tmp/conference_caller_name_" .. uid .. ".wav"; + name_file = "/var/spool/freeswitch/conference_caller_name_" .. uid .. ".wav"; caller.session:sayPhrase('conference_record_name'); session:recordFile(name_file, ANNOUNCEMENT_MAX_LEN, ANNOUNCEMENT_SILENCE_THRESHOLD, ANNOUNCEMENT_SILENCE_LEN); caller.session:streamFile(name_file); diff --git a/misc/freeswitch/scripts/common/group.lua b/misc/freeswitch/scripts/common/group.lua new file mode 100644 index 0000000..c4125bc --- /dev/null +++ b/misc/freeswitch/scripts/common/group.lua @@ -0,0 +1,88 @@ +-- Gemeinschaft 5 module: group class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + +Group = {} + +MAX_GROUP_MEMBERSHIPS = 256; + +-- create group object +function Group.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'group'; + self.log = arg.log; + self.database = arg.database; + return object; +end + +-- find group by id +function Group.find_by_id(self, id) + local sql_query = 'SELECT * FROM `groups` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1'; + local group = nil; + + self.database:query(sql_query, function(account_entry) + group = Group:new(self); + group.record = account_entry; + group.id = tonumber(account_entry.id); + group.name = account_entry.name; + end); + + return group; +end + +-- list groups by member permissions +function Group.name_id_by_permission(self, member_id, member_type, permission) + if not tonumber(member_id) then + return {}; + end + + local sql_query = 'SELECT DISTINCT `c`.`id`, `c`.`name` \ + FROM `group_permissions` `a` \ + JOIN `group_memberships` `b` ON `a`.`target_group_id` = `b`.`group_id` \ + JOIN `groups` `c` ON `c`.`id` = `b`.`group_id` \ + WHERE `b`.`item_type` = ' .. self.database:escape(member_type, '"') .. ' \ + AND `b`.`item_id` = ' .. member_id .. ' \ + AND `a`.`permission` = ' .. self.database:escape(permission, '"') .. ' \ + AND `c`.`active` IS TRUE \ + GROUP BY `b`.`group_id` LIMIT ' .. MAX_GROUP_MEMBERSHIPS; + + local group_names = {}; + local group_ids = {}; + + self.database:query(sql_query, function(account_entry) + table.insert(group_names, account_entry.name); + table.insert(group_ids, tonumber(account_entry.id)); + end); + + return group_names, group_ids; +end + +-- list groups by member +function Group.name_id_by_member(self, member_id, member_type) + if not tonumber(member_id) then + return {}; + end + + local sql_query = 'SELECT DISTINCT `c`.`id`, `c`.`name` \ + FROM `group_memberships` `b` \ + JOIN `groups` `c` ON `c`.`id` = `b`.`group_id` \ + WHERE `b`.`item_type` = ' .. self.database:escape(member_type, '"') .. ' \ + AND `b`.`item_id` = ' .. member_id .. ' \ + AND `c`.`active` IS TRUE \ + GROUP BY `b`.`group_id` LIMIT ' .. MAX_GROUP_MEMBERSHIPS; + + local group_names = {}; + local group_ids = {}; + + self.database:query(sql_query, function(account_entry) + table.insert(group_names, account_entry.name); + table.insert(group_ids, tonumber(account_entry.id)); + end); + + return group_names, group_ids; +end diff --git a/misc/freeswitch/scripts/common/phone_number.lua b/misc/freeswitch/scripts/common/phone_number.lua index 6635296..d6ee42a 100644 --- a/misc/freeswitch/scripts/common/phone_number.lua +++ b/misc/freeswitch/scripts/common/phone_number.lua @@ -55,6 +55,8 @@ function PhoneNumber.find_by_number(self, number, phone_numberable_types) self.database:query(sql_query, function(number_entry) phone_number = PhoneNumber:new(self); phone_number.record = number_entry; + phone_number.id = tonumber(number_entry.id); + phone_number.uuid = number_entry.uuid; end) return phone_number; @@ -68,6 +70,8 @@ function PhoneNumber.find_all_by_owner(self, owner_id, owner_type) self.database:query(sql_query, function(number_entry) phone_numbers[tonumber(number_entry.id)] = PhoneNumber:new(self); phone_numbers[tonumber(number_entry.id)].record = number_entry; + phone_numbers[tonumber(number_entry.id)].id = tonumber(number_entry.id); + phone_numbers[tonumber(number_entry.id)].uuid = number_entry.uuid; end) return phone_numbers; @@ -94,57 +98,6 @@ function PhoneNumber.list_by_same_owner(self, number, owner_types) end end --- Retrieve call forwarding -function PhoneNumber.call_forwarding(self, caller_ids) - require 'common.str' - - sources = sources or {}; - table.insert(sources, ''); - - local sql_query = 'SELECT \ - `a`.`destination` AS `number`, \ - `a`.`call_forwardable_id` AS `id`, \ - `a`.`call_forwardable_type` AS `type`, \ - `a`.`timeout`, `a`.`depth`, \ - `a`.`source`, \ - `b`.`value` AS `service` \ - FROM `call_forwards` `a` JOIN `call_forward_cases` `b` ON `a`.`call_forward_case_id` = `b`.`id` \ - WHERE `a`.`phone_number_id`= ' .. tonumber(self.record.id) .. ' \ - AND `a`.`active` IS TRUE'; - - local call_forwarding = {} - - self.database:query(sql_query, function(forwarding_entry) - local entry_match = false; - - if common.str.blank(forwarding_entry.source) then - entry_match = true; - else - local sources = common.str.strip_to_a(forwarding_entry.source, ',') - for index, source in ipairs(sources) do - for index, caller_id in ipairs(caller_ids) do - if caller_id:match(source) then - entry_match = true; - self.log:debug('CALL_FORWARDING_GET - source match: ', source, ' ~ ', caller_id ); - break; - end - end - end - end - - if entry_match then - call_forwarding[forwarding_entry.service] = forwarding_entry; - self.log:debug('CALL_FORWARDING_GET - PhoneNumber=', self.record.id, '/', self.record.uuid, '@', self.record.gs_node_id, - ', number: ', self.record.number, - ', service: ', forwarding_entry.service, - ', destination: ',forwarding_entry.type, '=', forwarding_entry.id, - ', number: ', forwarding_entry.number); - end - end) - - return call_forwarding; -end - function PhoneNumber.call_forwarding_effective(self, service, source) local conditions = {} diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua index 72ff388..541199f 100644 --- a/misc/freeswitch/scripts/common/str.lua +++ b/misc/freeswitch/scripts/common/str.lua @@ -146,3 +146,37 @@ end function blank(value) return (value == nil or to_s(value) == ''); end + +-- concatenate string to buffer +function append(buffer, value, separator, prefix, suffix) + separator = separator or ''; + prefix = prefix or ''; + suffix = suffix or ''; + if buffer ~= '' then + buffer = buffer .. separator .. prefix .. value .. suffix; + else + buffer = prefix .. value .. suffix; + end + + return buffer; +end + +-- concatenate array values to string +function concat(array, separator, prefix, suffix) + local buffer = ''; + for key, value in pairs(array) do + buffer = append(buffer, value, separator, prefix, suffix); + end + + return buffer; +end + +-- concatenate array keys to string +function concat_keys(array, separator, prefix, suffix) + local buffer = ''; + for key, value in pairs(array) do + buffer = append(buffer, key, separator, prefix, suffix); + end + + return buffer; +end diff --git a/misc/freeswitch/scripts/configuration.lua b/misc/freeswitch/scripts/configuration.lua index 75d0df3..6660c3d 100644 --- a/misc/freeswitch/scripts/configuration.lua +++ b/misc/freeswitch/scripts/configuration.lua @@ -79,6 +79,9 @@ function profile(database, sofia_ini, profile_name, index, domains, node_id) parameters['odbc-dsn'] = 'gemeinschaft:' .. tostring(database.user_name) .. ':' .. tostring(database.password); end + parameters['username'] = parameters['username'] or 'Gemeinschaft'; + parameters['user-agent-string'] = parameters['user-agent-string'] or 'Gemeinschaft'; + -- set local bind address if domains[index] then parameters['sip-ip'] = domains[index]['host']; diff --git a/misc/freeswitch/scripts/dialplan/call_parking.lua b/misc/freeswitch/scripts/dialplan/call_parking.lua index cc2cf4b..e51eb16 100644 --- a/misc/freeswitch/scripts/dialplan/call_parking.lua +++ b/misc/freeswitch/scripts/dialplan/call_parking.lua @@ -39,6 +39,22 @@ function CallParking.find_by_name(self, name) end +function CallParking.find_by_owner(self, owner_id, owner_type) + local sql_query = 'SELECT * FROM `parking_stalls` WHERE `parking_stallable_id` = '.. owner_id .. ' AND `parking_stallable_type` = "' .. owner_type .. '" ORDER BY `name`'; + local parking_stalls = {}; + + self.database:query(sql_query, function(entry) + local parking_stall = CallParking:new(self); + parking_stall.record = entry; + parking_stall.id = tonumber(entry.id); + parking_stall.name = entry.name; + table.insert(parking_stalls, parking_stall) + end) + + return parking_stalls; +end + + function CallParking.list_occupied(self, lot) lot = lot or self.lot; diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua index b27bb9d..7d9ac58 100644 --- a/misc/freeswitch/scripts/dialplan/dialplan.lua +++ b/misc/freeswitch/scripts/dialplan/dialplan.lua @@ -148,6 +148,9 @@ function Dialplan.object_find(self, class, identifier, auth_name) require 'common.str' class = common.str.downcase(class); + require 'common.group'; + local group_class = common.group.Group:new{ log = self.log, database = self.database }; + if class == 'user' then require 'dialplan.user' local user = nil; @@ -158,7 +161,8 @@ function Dialplan.object_find(self, class, identifier, auth_name) end if user then - user.groups = user:list_groups(); + user.user_groups = user:list_groups(); + user.groups = group_class:name_id_by_member(user.id, user.class); end return user; @@ -171,6 +175,10 @@ function Dialplan.object_find(self, class, identifier, auth_name) tenant = dialplan.tenant.Tenant:new{ log = self.log, database = self.database }:find_by_uuid(identifier); end + if tenant then + tenant.groups = group_class:name_id_by_member(tenant.id, tenant.class); + end + return tenant; elseif class == 'sipaccount' then require 'common.sip_account' @@ -184,6 +192,7 @@ function Dialplan.object_find(self, class, identifier, auth_name) end if sip_account then sip_account.owner = self:object_find(sip_account.record.sip_accountable_type, tonumber(sip_account.record.sip_accountable_id)); + sip_account.groups = group_class:name_id_by_member(sip_account.id, sip_account.class); end return sip_account; elseif class == 'huntgroup' then @@ -198,6 +207,7 @@ function Dialplan.object_find(self, class, identifier, auth_name) if hunt_group then hunt_group.owner = self:object_find('tenant', tonumber(hunt_group.record.tenant_id)); + hunt_group.groups = group_class:name_id_by_member(hunt_group.id, hunt_group.class); end return hunt_group; @@ -213,6 +223,7 @@ function Dialplan.object_find(self, class, identifier, auth_name) if acd then acd.owner = self:object_find(acd.record.automatic_call_distributorable_type, tonumber(acd.record.automatic_call_distributorable_id)); + acd.groups = group_class:name_id_by_member(acd.id, acd.class); end return acd; @@ -226,6 +237,7 @@ function Dialplan.object_find(self, class, identifier, auth_name) end if fax_account then fax_account.owner = self:object_find(fax_account.record.fax_accountable_type, tonumber(fax_account.record.fax_accountable_id)); + fax_account.groups = group_class:name_id_by_member(fax_account.id, fax_account.class); end return fax_account; @@ -235,7 +247,6 @@ end function Dialplan.retrieve_caller_data(self) require 'common.str' - self.caller.caller_phone_numbers_hash = {} -- TODO: Set auth_account on transfer initiated by calling party @@ -252,9 +263,9 @@ function Dialplan.retrieve_caller_data(self) end if self.caller.auth_account then - self.log:info('CALLER_DATA - auth account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid); + self.log:info('CALLER_DATA - auth account: ', self.caller.auth_account.class, '=', self.caller.auth_account.id, '/', self.caller.auth_account.uuid, ', groups: ', table.concat(self.caller.auth_account.groups, ',')); if self.caller.auth_account.owner then - self.log:info('CALLER_DATA - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid); + self.log:info('CALLER_DATA - auth owner: ', self.caller.auth_account.owner.class, '=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid, ', groups: ', table.concat(self.caller.auth_account.owner.groups, ',')); else self.log:error('CALLER_DATA - auth owner not found'); end @@ -273,9 +284,9 @@ function Dialplan.retrieve_caller_data(self) if not common.str.blank(self.caller.account.record.language_code) then self.caller.language = self.caller.account.record.language_code; end - self.log:info('CALLER_DATA - caller account: ', self.caller.account.class, '=', self.caller.account.id, '/', self.caller.account.uuid, ', phone_numbers: ', #self.caller.caller_phone_numbers, ', language: ', self.caller.language); + self.log:info('CALLER_DATA - caller account: ', self.caller.account.class, '=', self.caller.account.id, '/', self.caller.account.uuid, ', phone_numbers: ', #self.caller.caller_phone_numbers, ', language: ', self.caller.language, ', groups: ', table.concat(self.caller.account.groups, ',')); if self.caller.account.owner then - self.log:info('CALLER_DATA - caller owner: ', self.caller.account.owner.class, '=', self.caller.account.owner.id, '/', self.caller.account.owner.uuid); + self.log:info('CALLER_DATA - caller owner: ', self.caller.account.owner.class, '=', self.caller.account.owner.id, '/', self.caller.account.owner.uuid, ', groups: ', table.concat(self.caller.account.owner.groups, ',')); else self.log:error('CALLER_DATA - caller owner not found'); end @@ -319,7 +330,13 @@ function Dialplan.destination_new(self, arg) destination.uuid = common.str.to_s(destination.phone_number.record.phone_numberable_uuid); destination.node_id = common.str.to_i(destination.phone_number.record.gs_node_id); if self.caller then - destination.call_forwarding = destination.phone_number:call_forwarding(self.caller.caller_phone_numbers); + require 'common.call_forwarding'; + local call_forwarding_class = common.call_forwarding.CallForwarding:new{ log = self.log, database = self.database } + destination.call_forwarding = call_forwarding_class:list_by_owner(destination.id, destination.type, self.caller.caller_phone_numbers); + for service, call_forwarding_entry in pairs(call_forwarding_class:list_by_owner(destination.phone_number.id, destination.phone_number.class, self.caller.caller_phone_numbers)) do + destination.call_forwarding[service] = call_forwarding_entry; + end + -- destination.call_forwarding = destination.phone_number:call_forwarding(self.caller.caller_phone_numbers); end elseif destination.type == 'unknown' then require 'common.sip_account' @@ -362,64 +379,74 @@ end function Dialplan.dial(self, destination) + local user_id = nil; + local tenant_id = nil; + require 'common.str' destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1]; - if not self.caller.clir then - if destination.node_local and destination.type == 'sipaccount' then - local user_id = nil; - local tenant_id = nil; - - destination.account = self:object_find(destination.type, destination.id); - if destination.account then - if destination.account.class == 'sipaccount' then - destination.callee_id_name = destination.account.record.caller_name; - self.caller:set_callee_id(destination.number, destination.account.record.caller_name); - end + if destination.node_local and destination.type == 'sipaccount' then + destination.pickup_groups = {}; + + destination.account = self:object_find(destination.type, destination.id); + if destination.account then + if destination.account.class == 'sipaccount' then + destination.callee_id_name = destination.account.record.caller_name; + self.caller:set_callee_id(destination.number, destination.account.record.caller_name); + table.insert(destination.pickup_groups, 's' .. destination.account.id ); end + require 'common.group'; + local group_names, group_ids = common.group.Group:new{ log = self.log, database = self.database }:name_id_by_permission(destination.id, destination.type, 'pickup'); + self.log:debug('DESTINATION_GROUPS - pickup_groups: ', table.concat(group_names, ',')); + for index=1, #group_ids do + table.insert(destination.pickup_groups, 'g' .. group_ids[index]); + end + end - if destination.account and destination.account.owner then - if destination.account.owner.class == 'user' then - user_id = destination.account.owner.id; - tenant_id = tonumber(destination.account.owner.record.current_tenant_id); - elseif destination.account.owner.class == 'tenant' then - tenant_id = destination.account.owner.id; - end + if destination.account and destination.account.owner then + if destination.account.owner.class == 'user' then + user_id = destination.account.owner.id; + tenant_id = tonumber(destination.account.owner.record.current_tenant_id); + local user = self:object_find(destination.account.owner.class, tonumber(user_id)); + elseif destination.account.owner.class == 'tenant' then + tenant_id = destination.account.owner.id; end + end + end - if user_id or tenant_id then - require 'common.str' - local phone_book_entry = nil; + if not self.caller.clir then + if user_id or tenant_id then + require 'common.str' + local phone_book_entry = nil; - if self.phonebook_number_lookup then - require 'dialplan.phone_book' - phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant(self.caller.caller_phone_numbers, user_id, tenant_id); - end + if self.phonebook_number_lookup then + require 'dialplan.phone_book' + phone_book_entry = dialplan.phone_book.PhoneBook:new{ log = self.log, database = self.database }:find_entry_by_number_user_tenant(self.caller.caller_phone_numbers, user_id, tenant_id); + end - if phone_book_entry then - self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), caller_id_name: ', phone_book_entry.caller_id_name, ', ringtone: ', phone_book_entry.bellcore_id); - destination.caller_id_name = common.str.to_ascii(phone_book_entry.caller_id_name); - if tonumber(phone_book_entry.bellcore_id) then - self.log:debug('RINGTONE - phonebookentry, index: ', phone_book_entry.bellcore_id); - self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. phone_book_entry.bellcore_id .. ';x-line-id=0'); - end - if phone_book_entry.image then - self:set_caller_picture(phone_book_entry.id, 'phonebookentry', phone_book_entry.image); - elseif self.caller.account and self.caller.account.owner then - self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); - end + if phone_book_entry then + self.log:info('PHONE_BOOK_ENTRY - phone_book=', phone_book_entry.phone_book_id, ' (', phone_book_entry.phone_book_name, '), caller_id_name: ', phone_book_entry.caller_id_name, ', ringtone: ', phone_book_entry.bellcore_id); + destination.caller_id_name = common.str.to_ascii(phone_book_entry.caller_id_name); + if tonumber(phone_book_entry.bellcore_id) then + self.log:debug('RINGTONE - phonebookentry, index: ', phone_book_entry.bellcore_id); + self.caller:export_variable('alert_info', 'http://amooma.de;info=Ringer' .. phone_book_entry.bellcore_id .. ';x-line-id=0'); + end + if phone_book_entry.image then + self:set_caller_picture(phone_book_entry.id, 'phonebookentry', phone_book_entry.image); elseif self.caller.account and self.caller.account.owner then self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); - elseif self.geo_number_lookup then - require 'dialplan.geo_number' - local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.caller_id_number); - if geo_number then - self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country); - if geo_number.name then - destination.caller_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country); - else - destination.caller_id_name = common.str.to_ascii(geo_number.country); - end + end + elseif self.caller.account and self.caller.account.owner then + self:set_caller_picture(self.caller.account.owner.id, self.caller.account.owner.class); + elseif self.geo_number_lookup then + require 'dialplan.geo_number' + local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.caller_id_number); + if geo_number then + self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country); + if geo_number.name then + destination.caller_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country); + else + destination.caller_id_name = common.str.to_ascii(geo_number.country); end end end @@ -997,6 +1024,7 @@ function Dialplan.run(self, destination) destination = self:destination_new(result.call_forwarding); self.caller.destination = destination; + self.caller.destination_number = destination.number; if not result.no_cdr and auth_account then require 'common.call_history' diff --git a/misc/freeswitch/scripts/dialplan/dtmf.lua b/misc/freeswitch/scripts/dialplan/dtmf.lua index 4dbd35f..64f538e 100644 --- a/misc/freeswitch/scripts/dialplan/dtmf.lua +++ b/misc/freeswitch/scripts/dialplan/dtmf.lua @@ -17,12 +17,17 @@ function Dtmf.new(self, arg) self.bleg = arg.bleg self.digit_timeout = arg.digit_timeout or 5; self.router = arg.router; + self.digit_duration_min = arg.digit_duration_min or 500; return object; end function Dtmf.detect(self, caller, sequence, digit, duration, calee) + if not tonumber(duration) or duration < self.digit_duration_min then + return; + end + local timestamp = os.time(); if timestamp - sequence.updated > self.digit_timeout then sequence.digits = digit; @@ -63,6 +68,9 @@ function Dtmf.transfer(self, caller, destination, calee) caller:execute('transfer', destination); fapi:execute('uuid_kill', callee_uuid); else + if caller.account then + fapi:execute('uuid_setvar_multi', callee_uuid .. ' gs_auth_account_type=' .. caller.account.class .. ';gs_auth_account_uuid=' .. caller.account.uuid); + end fapi:execute('uuid_transfer', callee_uuid .. ' ' .. destination); caller.session:hangup(); end diff --git a/misc/freeswitch/scripts/dialplan/fax.lua b/misc/freeswitch/scripts/dialplan/fax.lua index 49a45d9..6dce0a9 100644 --- a/misc/freeswitch/scripts/dialplan/fax.lua +++ b/misc/freeswitch/scripts/dialplan/fax.lua @@ -4,7 +4,7 @@ module(...,package.seeall) -FAX_DOCUMENTS_DIRECTORY = '/tmp/' +FAX_SPOOL_DIRECTORY = '/var/spool/freeswitch/' FAX_PARALLEL_MAX = 8; Fax = {} @@ -18,7 +18,7 @@ function Fax.new(self, arg) self.log = arg.log; self.database = arg.database; self.record = arg.record; - self.fax_directory = arg.fax_directory or FAX_DOCUMENTS_DIRECTORY; + self.fax_spool_directory = arg.fax_spool_directory or FAX_SPOOL_DIRECTORY; return object; end @@ -79,7 +79,7 @@ end -- List waiting fax documents function Fax.queued_for_sending(self, limit) limit = limit or FAX_PARALLEL_MAX; - local sql_query = 'SELECT * FROM `fax_documents` WHERE `state` IN ("queued_for_sending","unsuccessful") AND `retry_counter` > 0 ORDER BY `sent_at` ASC LIMIT ' .. limit; + local sql_query = 'SELECT * FROM `fax_documents` WHERE `state` IN ("queued_for_sending","unsuccessful") AND `retry_counter` > 0 AND `tiff` IS NOT NULL AND `tiff` != "" ORDER BY `sent_at` ASC LIMIT ' .. limit; local fax_documents = {} self.database:query(sql_query, function(fax_entry) fax_entry['destination_numbers'] = Fax:destination_numbers(fax_entry.id) @@ -136,7 +136,7 @@ end -- Receive Fax function Fax.receive(self, caller, file_name) - file_name = file_name or self.fax_directory .. 'fax_in_' .. caller.uuid .. '.tiff'; + file_name = file_name or self.fax_spool_directory .. 'fax_in_' .. caller.uuid .. '.tiff'; caller:set_variable('fax_ident', self.record.station_id) caller:set_variable('fax_verbose', 'false') diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua index acfa336..3706872 100644 --- a/misc/freeswitch/scripts/dialplan/functions.lua +++ b/misc/freeswitch/scripts/dialplan/functions.lua @@ -35,10 +35,8 @@ function Functions.dialplan_function(self, caller, dialed_number) if fid == "ta" then result = self:transfer_all(caller, parameters[3]); - elseif fid == "in" then - result = self:intercept_extensions(caller, parameters[3]); elseif fid == "ia" then - result = self:intercept_any_extension(caller, parameters[3]); + result = self:intercept_any_number(caller, parameters[3]); elseif fid == "anc" then result = self:account_node_change(caller); elseif fid == "li" then @@ -113,9 +111,11 @@ function Functions.dialplan_function(self, caller, dialed_number) result = self:hangup(caller, parameters[3], parameters[4]); elseif fid == "cpa" then result = self:call_parking_inout(caller, parameters[3], parameters[4]); + elseif fid == "cpai" then + result = self:call_parking_inout_index(caller, parameters[3]); end - return result; + return result or { continue = false, code = 505, phrase = 'Error executing function', no_cdr = true }; end -- Transfer all calls to a conference @@ -149,94 +149,27 @@ function Functions.transfer_all(self, caller, destination_number) return destination_number; end --- Intercept Extensions -function Functions.intercept_extensions(self, caller, destination_numbers) - if type(destination_numbers) == "string" then - destination_numbers = "\"" .. destination_numbers .. "\""; - else - destination_numbers = "\"" .. table.concat(destination_numbers, "\",\"") .. "\""; - end - - self.log:debug("Intercept call to number(s): " .. destination_numbers); - - if caller.account_type ~= "SipAccount" then - self.log:error("caller is not a SipAccount"); - return { continue = false, code = 403, phrase = 'Incompatible caller' } - end - local sql_query = 'SELECT * FROM `channels` WHERE `callstate` IN ("EARLY", "ACTIVE") AND `dest` IN (' .. destination_numbers .. ') LIMIT 1'; - - self.database:query(sql_query, function(call_entry) - self.log:debug("intercepting call with uid: " .. call_entry.uuid); - caller:intercept(call_entry.uuid); - end) - - return nil; -end +function Functions.intercept_any_number(self, caller, destination_number) + require 'common.phone_number' + local phone_number = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(destination_number); --- intercept call to destination (e.g. sip_account) -function Functions.intercept_destination(self, caller, destination) - self.log:debug("Intercept call to destination " .. destination); - local result = false; - local sql_query = 'SELECT `call_uuid`, `uuid` FROM `channels` WHERE `callstate` = "RINGING" AND `dest` = "' .. destination .. '" LIMIT 1'; + if not phone_number or not phone_number.record then + self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - number not found: ', destination_number); + return { continue = false, code = 404, phrase = 'Number not found', no_cdr = true }; + end - caller:set_caller_id(caller.caller_phone_numbers[1] ,caller.caller_id_name); - self.database:query(sql_query, function(call_entry) - if call_entry.call_uuid and tostring(call_entry.call_uuid) then - self.log:debug("intercepting call - uuid: " .. call_entry.call_uuid); - caller:intercept(call_entry.call_uuid); - result = { continue = false, code = 200, call_service = 'pickup' } - require 'common.str' - require 'common.fapi' - local fapi = common.fapi.FApi:new{ log = self.log, uuid = call_entry.call_uuid } - if fapi:channel_exists() then - caller:set_caller_id( - common.str.to_s(fapi:get_variable('effective_caller_id_number')), - common.str.to_s(fapi:get_variable('effective_caller_id_name')) - ); - caller:set_callee_id( - common.str.to_s(fapi:get_variable('effective_callee_id_number')), - common.str.to_s(fapi:get_variable('effective_callee_id_name')) - ); - - caller:set_variable('gs_destination_type', fapi:get_variable('gs_destination_type')); - caller:set_variable('gs_destination_id', fapi:get_variable('gs_destination_id')); - caller:set_variable('gs_destination_uuid', fapi:get_variable('gs_destination_uuid')); - - caller:set_variable('gs_caller_account_type', fapi:get_variable('gs_account_type')); - caller:set_variable('gs_caller_account_id', fapi:get_variable('gs_account_id')); - caller:set_variable('gs_caller_account_uuid', fapi:get_variable('gs_account_uuid')); - - caller:set_variable('gs_auth_account_type', fapi:get_variable('gs_auth_account_type')); - caller:set_variable('gs_auth_account_id', fapi:get_variable('gs_auth_account_id')); - caller:set_variable('gs_auth_account_uuid', fapi:get_variable('gs_auth_account_uuid')); - end - else - self.log:error('FUNCTION - failed to intercept call - no caller uuid for callee uuid: ', call_entry.uuid); - end - end) + if not phone_number.record.phone_numberable_type:lower() == 'sipaccount' or not tonumber(phone_number.record.phone_numberable_id) then + self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - destination: ', phone_number.record.phone_numberable_type:lower(), '=', phone_number.record.phone_numberable_id, ', number: ', destination_number); + return { continue = false, code = 505, phrase = 'Incompatible destination', no_cdr = true }; + end - return result; -end + self.log:info('FUNCTION_INTERCEPT_ANY_NUMBER intercepting call - to: ', phone_number.record.phone_numberable_type:lower(), '=', phone_number.record.phone_numberable_id, ', number: ', destination_number); --- intercept call to owner of destination_number -function Functions.intercept_any_extension(self, caller, destination_number) - require 'common.phone_number' - local phone_number_object = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(destination_number); + caller:set_variable('gs_pickup_group_pick', 's' .. phone_number.record.phone_numberable_id); + caller:execute('pickup', 's' .. phone_number.record.phone_numberable_id); - if not phone_number_object or not phone_number_object.record then - self.log:notice("unallocated number: " .. tostring(destination_number)); - return false; - end - - if phone_number_object.record.phone_numberable_type == 'SipAccount' then - require "common.sip_account" - local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database } - local sip_account = sip_account_class:find_by_id(phone_number_object.record.phone_numberable_id) - if sip_account then - return self:intercept_destination(caller, sip_account.record.auth_name); - end - end + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } end @@ -932,3 +865,39 @@ function Functions.call_parking_inout(self, caller, stall_name, lot_name) return { continue = false, code = 200, phrase = 'OK', no_cdr = true } end + + +function Functions.call_parking_inout_index(self, caller, stall_index) + if not tonumber(stall_index) then + self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - malformed index: ', stall_index); + return { continue = false, code = 404, phrase = 'No parkings stall specified', no_cdr = true } + end + + require 'common.str'; + local owner = common.str.try(caller, 'auth_account.owner'); + + if not owner then + self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - stall owner not specified'); + return { continue = false, code = 404, phrase = 'No parkings stalls owner' , no_cdr = true } + end + + require 'dialplan.call_parking'; + local parking_stalls = dialplan.call_parking.CallParking:new{ log = self.log, database = self.database, caller = caller }:find_by_owner(owner.id, owner.class); + + if not parking_stalls or #parking_stalls < 1 then + self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - no parkings stalls found'); + return { continue = false, code = 404, phrase = 'No parkings stalls', no_cdr = true } + end + + local parking_stall = parking_stalls[tonumber(stall_index)]; + + if not parking_stall then + self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - no parkings stall found with index: ', stall_index); + return { continue = false, code = 404, phrase = 'Parking stall not found', no_cdr = true } + end + + self.log:info('FUNCTION_CALL_PARKING_INOUT_INDEX parking/retrieving call - parkingstall=', parking_stall.id, '/', parking_stall.name, ', index: ', stall_index); + parking_stall:park_retrieve(); + + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua index b56f1b2..5c98792 100644 --- a/misc/freeswitch/scripts/dialplan/sip_call.lua +++ b/misc/freeswitch/scripts/dialplan/sip_call.lua @@ -76,7 +76,8 @@ end function SipCall.fork(self, destinations, arg ) - local dial_strings = {} + local dial_strings = {}; + local pickup_groups = {}; require 'common.sip_account' require 'common.str' @@ -135,6 +136,11 @@ function SipCall.fork(self, destinations, arg ) 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); + if destination.pickup_groups and #destination.pickup_groups > 0 then + for key=1, #destination.pickup_groups do + pickup_groups[destination.pickup_groups[key]] = true; + end + end else some_destinations_busy = true; call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' }; @@ -184,6 +190,10 @@ function SipCall.fork(self, destinations, arg ) self.caller:set_variable('call_timeout', arg.timeout ); self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout); + for pickup_group, value in pairs(pickup_groups) do + table.insert(dial_strings, 'pickup/' .. pickup_group); + end + if arg.send_ringing then self.caller:execute('ring_ready'); end @@ -201,10 +211,20 @@ 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 + if not destination then + destination = { + ['type'] = session_callee:getVariable('gs_account_type'); + id = session_callee:getVariable('gs_account_id'); + uuid = session_callee:getVariable('gs_account_uuid'); + pickup_group_pick = session_callee:getVariable('gs_pickup_group_pick'); + } + self.log:notice('FORK - call picked off by: ', destination.type, '=', destination.id, '/', destination.uuid, ', pickup_group: ', destination.pickup_group_pick); + end + + if arg.detect_dtmf_after_bridge_caller and self.caller.auth_account then session:execute('start_dtmf'); end - if arg.detect_dtmf_after_bridge_callee then + if arg.detect_dtmf_after_bridge_callee and destination.type == 'sipaccount' then session_callee:execute('start_dtmf'); end if arg.bypass_media_network then diff --git a/misc/freeswitch/scripts/dialplan/user.lua b/misc/freeswitch/scripts/dialplan/user.lua index b536600..b6928b4 100644 --- a/misc/freeswitch/scripts/dialplan/user.lua +++ b/misc/freeswitch/scripts/dialplan/user.lua @@ -69,6 +69,23 @@ function User.list_groups(self, id) end +function User.list_group_ids(self, id) + require 'common.str' + id = id or self.id; + local sql_query = 'SELECT `b`.`id` FROM `user_group_memberships` `a` \ + JOIN `user_groups` `b` ON `a`.`user_group_id` = `b`.`id` \ + WHERE `a`.`state` = "active" AND `a`.`user_id`= ' .. tonumber(id) .. ' ORDER BY `b`.`position` LIMIT ' .. MAX_GROUP_MEMBERSHIPS; + + local groups = {}; + + self.database:query(sql_query, function(entry) + table.insert(groups, common.str.downcase(entry.id)); + end); + + return groups; +end + + function User.check_pin(self, pin_to_check) if not self.record then return nil diff --git a/misc/freeswitch/scripts/dialplan/voicemail.lua b/misc/freeswitch/scripts/dialplan/voicemail.lua index 4c96fbe..ae7d0a1 100644 --- a/misc/freeswitch/scripts/dialplan/voicemail.lua +++ b/misc/freeswitch/scripts/dialplan/voicemail.lua @@ -11,7 +11,7 @@ MESSAGE_LENGTH_MAX = 120; SILENCE_LENGTH_ABORT = 5; SILENCE_LEVEL = 500; BEEP = 'tone_stream://%(1000,0,500)'; -RECORD_FILE_PREFIX = '/tmp/voicemail_'; +RECORD_FILE_PREFIX = '/var/spool/freeswitch/voicemail_'; -- create voicemail object function Voicemail.new(self, arg) diff --git a/misc/freeswitch/scripts/send_fax.lua b/misc/freeswitch/scripts/send_fax.lua index 4898cb8..d717f93 100644 --- a/misc/freeswitch/scripts/send_fax.lua +++ b/misc/freeswitch/scripts/send_fax.lua @@ -2,7 +2,6 @@ -- (c) AMOOMA GmbH 2012-2013 -- -local FAX_FILE_PATH = "/opt/GS5/public/uploads/fax_document/tiff/"; local FAX_ANSWERING_TIMEOUT = 20; -- Set logger @@ -142,13 +141,11 @@ end if session and session:answered() then log:info('FAX_SEND - sending fax_document=' .. fax_document.id .. ' (' .. fax_document.tiff .. ')'); - local file_name = FAX_FILE_PATH .. fax_document.id .. "/" .. fax_document.tiff; - session:setVariable('fax_ident', fax_account.record.station_id) session:setVariable('fax_header', fax_account.record.name) session:setVariable('fax_verbose', 'false') local start_time = os.time(); - session:execute('txfax', file_name); + session:execute('txfax', fax_document.tiff); fax_state = { state = nil, diff --git a/script/logout_phones.sh b/script/logout_phones.sh new file mode 100755 index 0000000..41e2a40 --- /dev/null +++ b/script/logout_phones.sh @@ -0,0 +1,3 @@ +#! /bin/bash +cd /opt/GS5/script/ +/opt/GS5/script/logout_phones $@ diff --git a/test/functional/group_memberships_controller_test.rb b/test/functional/group_memberships_controller_test.rb new file mode 100644 index 0000000..596de1f --- /dev/null +++ b/test/functional/group_memberships_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GroupMembershipsControllerTest < ActionController::TestCase + setup do + @group_membership = group_memberships(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:group_memberships) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create group_membership" do + assert_difference('GroupMembership.count') do + post :create, group_membership: @group_membership.attributes + end + + assert_redirected_to group_membership_path(assigns(:group_membership)) + end + + test "should show group_membership" do + get :show, id: @group_membership.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @group_membership.to_param + assert_response :success + end + + test "should update group_membership" do + put :update, id: @group_membership.to_param, group_membership: @group_membership.attributes + assert_redirected_to group_membership_path(assigns(:group_membership)) + end + + test "should destroy group_membership" do + assert_difference('GroupMembership.count', -1) do + delete :destroy, id: @group_membership.to_param + end + + assert_redirected_to group_memberships_path + end +end diff --git a/test/functional/group_permissions_controller_test.rb b/test/functional/group_permissions_controller_test.rb new file mode 100644 index 0000000..4b70ae3 --- /dev/null +++ b/test/functional/group_permissions_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GroupPermissionsControllerTest < ActionController::TestCase + setup do + @group_permission = group_permissions(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:group_permissions) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create group_permission" do + assert_difference('GroupPermission.count') do + post :create, group_permission: @group_permission.attributes + end + + assert_redirected_to group_permission_path(assigns(:group_permission)) + end + + test "should show group_permission" do + get :show, id: @group_permission.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @group_permission.to_param + assert_response :success + end + + test "should update group_permission" do + put :update, id: @group_permission.to_param, group_permission: @group_permission.attributes + assert_redirected_to group_permission_path(assigns(:group_permission)) + end + + test "should destroy group_permission" do + assert_difference('GroupPermission.count', -1) do + delete :destroy, id: @group_permission.to_param + end + + assert_redirected_to group_permissions_path + end +end diff --git a/test/functional/groups_controller_test.rb b/test/functional/groups_controller_test.rb new file mode 100644 index 0000000..2981018 --- /dev/null +++ b/test/functional/groups_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class GroupsControllerTest < ActionController::TestCase + setup do + @group = groups(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:groups) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create group" do + assert_difference('Group.count') do + post :create, group: @group.attributes + end + + assert_redirected_to group_path(assigns(:group)) + end + + test "should show group" do + get :show, id: @group.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @group.to_param + assert_response :success + end + + test "should update group" do + put :update, id: @group.to_param, group: @group.attributes + assert_redirected_to group_path(assigns(:group)) + end + + test "should destroy group" do + assert_difference('Group.count', -1) do + delete :destroy, id: @group.to_param + end + + assert_redirected_to groups_path + end +end diff --git a/test/functional/restore_jobs_controller_test.rb b/test/functional/restore_jobs_controller_test.rb new file mode 100644 index 0000000..bd06b25 --- /dev/null +++ b/test/functional/restore_jobs_controller_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' + +class RestoreJobsControllerTest < ActionController::TestCase + setup do + @restore_job = restore_jobs(:one) + end + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:restore_jobs) + end + + test "should get new" do + get :new + assert_response :success + end + + test "should create restore_job" do + assert_difference('RestoreJob.count') do + post :create, restore_job: @restore_job.attributes + end + + assert_redirected_to restore_job_path(assigns(:restore_job)) + end + + test "should show restore_job" do + get :show, id: @restore_job.to_param + assert_response :success + end + + test "should get edit" do + get :edit, id: @restore_job.to_param + assert_response :success + end + + test "should update restore_job" do + put :update, id: @restore_job.to_param, restore_job: @restore_job.attributes + assert_redirected_to restore_job_path(assigns(:restore_job)) + end + + test "should destroy restore_job" do + assert_difference('RestoreJob.count', -1) do + delete :destroy, id: @restore_job.to_param + end + + assert_redirected_to restore_jobs_path + end +end diff --git a/test/unit/group_membership_test.rb b/test/unit/group_membership_test.rb new file mode 100644 index 0000000..3719323 --- /dev/null +++ b/test/unit/group_membership_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GroupMembershipTest < ActiveSupport::TestCase + def test_should_be_valid + assert GroupMembership.new.valid? + end +end diff --git a/test/unit/group_permission_test.rb b/test/unit/group_permission_test.rb new file mode 100644 index 0000000..44e0b28 --- /dev/null +++ b/test/unit/group_permission_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GroupPermissionTest < ActiveSupport::TestCase + def test_should_be_valid + assert GroupPermission.new.valid? + end +end diff --git a/test/unit/group_test.rb b/test/unit/group_test.rb new file mode 100644 index 0000000..68ecdc0 --- /dev/null +++ b/test/unit/group_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class GroupTest < ActiveSupport::TestCase + def test_should_be_valid + assert Group.new.valid? + end +end diff --git a/test/unit/restore_job_test.rb b/test/unit/restore_job_test.rb new file mode 100644 index 0000000..ce69ced --- /dev/null +++ b/test/unit/restore_job_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class RestoreJobTest < ActiveSupport::TestCase + def test_should_be_valid + assert RestoreJob.new.valid? + end +end |