diff options
author | Stefan Wintermeyer <stefan.wintermeyer@amooma.de> | 2013-01-05 23:10:07 +0100 |
---|---|---|
committer | Stefan Wintermeyer <stefan.wintermeyer@amooma.de> | 2013-01-05 23:10:07 +0100 |
commit | 3862734b5e0833ed108300102c68159e40ffd93a (patch) | |
tree | 4491044dbf48aea515303382e7664cf9be2cb182 /app/models | |
parent | 380a4cdfe5cfa573fb916ca7c2145a6062ef8198 (diff) | |
parent | 57196d838691aeba38ad7e088e83c0881a213861 (diff) |
Merge branch 'replace_constants' into develop
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/ability.rb | 2 | ||||
-rw-r--r-- | app/models/access_authorization.rb | 4 | ||||
-rw-r--r-- | app/models/api/row.rb | 2 | ||||
-rw-r--r-- | app/models/call_forward.rb | 2 | ||||
-rw-r--r-- | app/models/conference.rb | 4 | ||||
-rw-r--r-- | app/models/conference_invitee.rb | 2 | ||||
-rw-r--r-- | app/models/fax_document.rb | 4 | ||||
-rw-r--r-- | app/models/gs_cluster_sync_log_entry.rb | 4 | ||||
-rw-r--r-- | app/models/gs_parameter.rb | 37 | ||||
-rw-r--r-- | app/models/hunt_group.rb | 8 | ||||
-rw-r--r-- | app/models/phone_number.rb | 16 | ||||
-rw-r--r-- | app/models/phone_number_range.rb | 2 | ||||
-rw-r--r-- | app/models/sip_account.rb | 4 | ||||
-rw-r--r-- | app/models/tenant.rb | 22 | ||||
-rw-r--r-- | app/models/user.rb | 3 |
15 files changed, 78 insertions, 38 deletions
diff --git a/app/models/ability.rb b/app/models/ability.rb index d9ec74a..f4068ca 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -70,7 +70,7 @@ class Ability # Dirty hack to disable PhoneNumberRange in the GUI # - if STRICT_INTERNAL_EXTENSION_HANDLING == false + if GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') == false cannot :manage, PhoneNumberRange end else diff --git a/app/models/access_authorization.rb b/app/models/access_authorization.rb index ef33115..878799a 100644 --- a/app/models/access_authorization.rb +++ b/app/models/access_authorization.rb @@ -18,7 +18,9 @@ class AccessAuthorization < ActiveRecord::Base :allow_nil => true, :allow_blank => true, :message => "must be numeric." - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + validates_length_of :pin, + :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), + :maximum => (GsParameter.get('MAXIMUM_PIN_LENGTH').nil? ? 10 : GsParameter.get('MAXIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true has_many :phone_numbers, :as => :phone_numberable, :dependent => :destroy diff --git a/app/models/api/row.rb b/app/models/api/row.rb index ac35516..e82a3e2 100644 --- a/app/models/api/row.rb +++ b/app/models/api/row.rb @@ -28,7 +28,7 @@ class Api::Row < ActiveRecord::Base end def create_a_new_gemeinschaft_user - tenant = Tenant.find(DEFAULT_API_TENANT_ID) + tenant = Tenant.find(GsParameter.get('DEFAULT_API_TENANT_ID')) # Find or create the user # diff --git a/app/models/call_forward.rb b/app/models/call_forward.rb index 0018cfb..8a8d1df 100644 --- a/app/models/call_forward.rb +++ b/app/models/call_forward.rb @@ -28,7 +28,7 @@ class CallForward < ActiveRecord::Base validates_numericality_of :depth, :only_integer => true, :greater_than_or_equal_to => 1, - :less_than_or_equal_to => MAX_CALL_FORWARD_DEPTH + :less_than_or_equal_to => (GsParameter.get('MAX_CALL_FORWARD_DEPTH').nil? ? 0 : GsParameter.get('MAX_CALL_FORWARD_DEPTH')) before_validation { self.timeout = nil if self.call_forward_case_id != 3 diff --git a/app/models/conference.rb b/app/models/conference.rb index 8be9f21..16b646c 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -15,7 +15,7 @@ class Conference < ActiveRecord::Base validates_presence_of :max_members validates_numericality_of :max_members, :only_integer => true, :greater_than => 0, - :less_than => (MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE + 1), + :less_than => ((GsParameter.get('MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE').nil? ? 10 : GsParameter.get('MAXIMUM_NUMBER_OF_PEOPLE_IN_A_CONFERENCE')) + 1), :allow_nil => false, :allow_blank => false @@ -25,7 +25,7 @@ class Conference < ActiveRecord::Base :greater_than => 0, :allow_nil => true, :allow_blank => true - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true diff --git a/app/models/conference_invitee.rb b/app/models/conference_invitee.rb index 7de20de..d6e3bac 100644 --- a/app/models/conference_invitee.rb +++ b/app/models/conference_invitee.rb @@ -13,7 +13,7 @@ class ConferenceInvitee < ActiveRecord::Base :greater_than => 0, :allow_nil => true, :allow_blank => true - validates_length_of :pin, :minimum => MINIMUM_PIN_LENGTH, + validates_length_of :pin, :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), :allow_nil => true, :allow_blank => true diff --git a/app/models/fax_document.rb b/app/models/fax_document.rb index 67bdea9..080bdaa 100644 --- a/app/models/fax_document.rb +++ b/app/models/fax_document.rb @@ -54,7 +54,7 @@ class FaxDocument < ActiveRecord::Base private def render_thumbnails - directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/fax_thumbnails/#{self.id}" + directory = "/tmp/GS-#{GsParameter.get('GEMEINSCHAFT_VERSION')}/fax_thumbnails/#{self.id}" system('mkdir -p ' + directory) system("cd #{directory} && convert #{Rails.root.to_s}/public#{self.document.to_s}[0-100] -colorspace Gray PNG:'fax_page.png'") number_of_thumbnails = Dir["#{directory}/fax_page-*.png"].count @@ -70,7 +70,7 @@ class FaxDocument < ActiveRecord::Base def convert_pdf_to_tiff page_size_a4 = '595 842' page_size_command = "<< /Policies << /PageSize 3 >> /InputAttributes currentpagedevice /InputAttributes get dup { pop 1 index exch undef } forall dup 0 << /PageSize [ #{page_size_a4} ] >> put >> setpagedevice" - directory = "/tmp/GS-#{GEMEINSCHAFT_VERSION}/faxes/#{self.id}" + directory = "/tmp/GS-#{GsParameter.get('GEMEINSCHAFT_VERSION')}/faxes/#{self.id}" system('mkdir -p ' + directory) tiff_file_name = File.basename(self.document.to_s.downcase, ".pdf") + '.tiff' system "cd #{directory} && gs -q -r#{self.fax_resolution.resolution_value} -dNOPAUSE -dBATCH -dSAFER -sDEVICE=tiffg3 -sOutputFile=\"#{tiff_file_name}\" -c \"#{page_size_command}\" -- \"#{Rails.root.to_s}/public#{self.document.to_s}\"" diff --git a/app/models/gs_cluster_sync_log_entry.rb b/app/models/gs_cluster_sync_log_entry.rb index 063ff23..51e3b05 100644 --- a/app/models/gs_cluster_sync_log_entry.rb +++ b/app/models/gs_cluster_sync_log_entry.rb @@ -15,7 +15,7 @@ class GsClusterSyncLogEntry < ActiveRecord::Base after_create :apply_to_local_database def apply_to_local_database - if self.homebase_ip_address != HOMEBASE_IP_ADDRESS + if self.homebase_ip_address != GsParameter.get('HOMEBASE_IP_ADDRESS') if self.class_name.constantize.new.attribute_names.include?('is_native') case self.action when 'create' @@ -84,7 +84,7 @@ class GsClusterSyncLogEntry < ActiveRecord::Base end def populate_other_cluster_nodes - if self.homebase_ip_address == HOMEBASE_IP_ADDRESS && self.waiting_to_be_synced == true + if self.homebase_ip_address == GsParameter.get('HOMEBASE_IP_ADDRESS') && self.waiting_to_be_synced == true if GsNode.where(:push_updates_to => true).count > 0 GsNode.where(:push_updates_to => true).each do |gs_node| RemoteGsNode::GsClusterSyncLogEntry.site = gs_node.site diff --git a/app/models/gs_parameter.rb b/app/models/gs_parameter.rb new file mode 100644 index 0000000..9d9e996 --- /dev/null +++ b/app/models/gs_parameter.rb @@ -0,0 +1,37 @@ +class GsParameter < ActiveRecord::Base + attr_accessible :name, :section, :value, :class_type, :description + + validates :name, + :presence => true, + :uniqueness => true + + validates :value, + :presence => true + + validates :class_type, + :presence => true, + :inclusion => { :in => ['String', 'Integer', 'Boolean', 'YAML'] } + + def self.get(wanted_variable) + if GsParameter.table_exists? + item = GsParameter.where(:name => wanted_variable).first + if item.nil? + return nil + else + return item.value.to_i if item.class_type == 'Integer' + return item.value.to_s if item.class_type == 'String' + if item.class_type == 'Boolean' + return true if item.value == 'true' + return false if item.value == 'false' + end + return YAML.load(item.value) if item.class_type == 'YAML' + end + else + nil + end + end + + def to_s + name + end +end diff --git a/app/models/hunt_group.rb b/app/models/hunt_group.rb index 276ae53..184297c 100644 --- a/app/models/hunt_group.rb +++ b/app/models/hunt_group.rb @@ -8,17 +8,17 @@ class HuntGroup < ActiveRecord::Base :allow_nil => true, :allow_blank => true validates_presence_of :strategy - validates_inclusion_of :strategy, :in => HUNT_GROUP_STRATEGIES + validates_inclusion_of :strategy, :in => (GsParameter.get('HUNT_GROUP_STRATEGIES').nil? ? [] : GsParameter.get('HUNT_GROUP_STRATEGIES')) validates_presence_of :seconds_between_jumps, :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_numericality_of :seconds_between_jumps, :only_integer => true, - :greater_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.min, - :less_than_or_equal_to => VALID_SECONDS_BETWEEN_JUMPS_VALUES.max, + :greater_than_or_equal_to => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? 2 : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').min), + :less_than_or_equal_to => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? 120 : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').max), :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_inclusion_of :seconds_between_jumps, - :in => VALID_SECONDS_BETWEEN_JUMPS_VALUES, + :in => (GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES').nil? ? [] : GsParameter.get('VALID_SECONDS_BETWEEN_JUMPS_VALUES')), :if => Proc.new{ |hunt_group| hunt_group.strategy != 'ring_all' } validates_inclusion_of :seconds_between_jumps, :in => [nil], diff --git a/app/models/phone_number.rb b/app/models/phone_number.rb index 4c0cf46..d1e950f 100644 --- a/app/models/phone_number.rb +++ b/app/models/phone_number.rb @@ -18,8 +18,8 @@ class PhoneNumber < ActiveRecord::Base before_save :save_value_of_to_s after_create :copy_existing_call_forwards_if_necessary before_validation :'parse_and_split_number!' - validate :validate_number, :if => Proc.new { |phone_number| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } - validate :check_if_number_is_available, :if => Proc.new { |phone_number| STRICT_INTERNAL_EXTENSION_HANDLING && STRICT_DID_HANDLING } + validate :validate_number, :if => Proc.new { |phone_number| GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') && GsParameter.get('STRICT_DID_HANDLING') } + validate :check_if_number_is_available, :if => Proc.new { |phone_number| GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') && GsParameter.get('STRICT_DID_HANDLING') } acts_as_list :scope => [:phone_numberable_id, :phone_numberable_type] @@ -95,7 +95,7 @@ class PhoneNumber < ActiveRecord::Base else # Check if the number is an internal extension. if tenant - internal_extension_range = tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first + internal_extension_range = tenant.phone_number_ranges.where(:name => GsParameter.get('INTERNAL_EXTENSIONS')).first if internal_extension_range if internal_extension_range.phone_numbers.where(:number => number).length > 0 parts[:extension] = number @@ -192,8 +192,8 @@ class PhoneNumber < ActiveRecord::Base end def parse_and_split_number! - if self.phone_numberable_type == 'PhoneNumberRange' && self.phone_numberable.name == INTERNAL_EXTENSIONS - # The parent is the PhoneNumberRange INTERNAL_EXTENSIONS. Therefor it must be an extensions. + if self.phone_numberable_type == 'PhoneNumberRange' && self.phone_numberable.name == GsParameter.get('INTERNAL_EXTENSIONS') + # The parent is the PhoneNumberRange GsParameter.get('INTERNAL_EXTENSIONS'). Therefor it must be an extensions. # self.country_code = nil self.area_code = nil @@ -202,8 +202,8 @@ class PhoneNumber < ActiveRecord::Base self.extension = self.number.to_s.strip else if self.tenant && - self.tenant.phone_number_ranges.exists?(:name => INTERNAL_EXTENSIONS) && - self.tenant.phone_number_ranges.where(:name => INTERNAL_EXTENSIONS).first.phone_numbers.exists?(:number => self.number) + self.tenant.phone_number_ranges.exists?(:name => GsParameter.get('INTERNAL_EXTENSIONS')) && + self.tenant.phone_number_ranges.where(:name => GsParameter.get('INTERNAL_EXTENSIONS')).first.phone_numbers.exists?(:number => self.number) self.country_code = nil self.area_code = nil self.subscriber_number = nil @@ -263,7 +263,7 @@ class PhoneNumber < ActiveRecord::Base if self.phone_numberable_type != 'PhoneBookEntry' && self.tenant phone_number_ranges = self.tenant.phone_number_ranges.where( - :name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS] + :name => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')] ) if !phone_number_ranges.empty? if !PhoneNumber.where(:phone_numberable_type => 'PhoneNumberRange'). diff --git a/app/models/phone_number_range.rb b/app/models/phone_number_range.rb index 2fdd9b6..b666487 100644 --- a/app/models/phone_number_range.rb +++ b/app/models/phone_number_range.rb @@ -6,7 +6,7 @@ class PhoneNumberRange < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => [:phone_number_rangeable_id, :phone_number_rangeable_type] - validates_inclusion_of :name, :in => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS, SERVICE_NUMBERS] + validates_inclusion_of :name, :in => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS'), GsParameter.get('SERVICE_NUMBERS')] validates_presence_of :phone_number_rangeable_id validates_presence_of :phone_number_rangeable diff --git a/app/models/sip_account.rb b/app/models/sip_account.rb index 8459265..5388395 100644 --- a/app/models/sip_account.rb +++ b/app/models/sip_account.rb @@ -71,7 +71,7 @@ class SipAccount < ActiveRecord::Base after_update :log_out_phone_if_not_local def to_s - truncate((self.caller_name || "SipAccount ID #{self.id}"), :length => TO_S_MAX_CALLER_NAME_LENGTH) + " (#{truncate(self.auth_name, :length => TO_S_MAX_LENGTH_OF_AUTH_NAME)}@...#{self.host.split(/\./)[2,3].to_a.join('.') if self.host })" + truncate((self.caller_name || "SipAccount ID #{self.id}"), :length => GsParameter.get('TO_S_MAX_CALLER_NAME_LENGTH')) + " (#{truncate(self.auth_name, :length => GsParameter.get('TO_S_MAX_LENGTH_OF_AUTH_NAME'))}@...#{self.host.split(/\./)[2,3].to_a.join('.') if self.host })" end def call_forwarding_toggle( call_forwarding_service, to_voicemail = nil ) @@ -200,7 +200,7 @@ class SipAccount < ActiveRecord::Base # log out phone if sip_account is not on this node def log_out_phone_if_not_local - if self.gs_node_id && ! GsNode.where(:ip_address => HOMEBASE_IP_ADDRESS, :id => self.gs_node_id).first + if self.gs_node_id && ! GsNode.where(:ip_address => GsParameter.get('HOMEBASE_IP_ADDRESS'), :id => self.gs_node_id).first self.phones.each do |phone| phone.user_logout; end diff --git a/app/models/tenant.rb b/app/models/tenant.rb index d9351b7..c3e2926 100644 --- a/app/models/tenant.rb +++ b/app/models/tenant.rb @@ -3,11 +3,11 @@ class Tenant < ActiveRecord::Base attr_accessible :name, :description, :sip_domain_id, :country_id, :language_id, :from_field_pin_change_email, :from_field_voicemail_email - if STRICT_INTERNAL_EXTENSION_HANDLING == true + if GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') == true attr_accessible :internal_extension_ranges end - if STRICT_DID_HANDLING == true + if GsParameter.get('STRICT_DID_HANDLING') == true attr_accessible :did_list end @@ -93,7 +93,7 @@ class Tenant < ActiveRecord::Base name end - if STRICT_INTERNAL_EXTENSION_HANDLING == true + if GsParameter.get('STRICT_INTERNAL_EXTENSION_HANDLING') == true def array_of_internal_extension_numbers ranges = self.internal_extension_ranges.gsub(/[^0-9\-,]/,'').gsub(/[\-]+/,'-').gsub(/[,]+/,',').split(/,/) output = [] @@ -112,7 +112,7 @@ class Tenant < ActiveRecord::Base # Generate the internal_extensions # def generate_internal_extensions - internal_extensions = self.phone_number_ranges.find_or_create_by_name(INTERNAL_EXTENSIONS, :description => 'A list of all available internal extensions.') + internal_extensions = self.phone_number_ranges.find_or_create_by_name(GsParameter.get('INTERNAL_EXTENSIONS'), :description => 'A list of all available internal extensions.') phone_number_list = Array.new @@ -122,7 +122,7 @@ class Tenant < ActiveRecord::Base elsif # Don't create extensions like 911, 110 or 112 (at least by default) # - phone_number_list = (self.array_of_internal_extension_numbers - self.country.phone_number_ranges.where(:name => SERVICE_NUMBERS).first.phone_numbers.map{|entry| entry.number}) + phone_number_list = (self.array_of_internal_extension_numbers - self.country.phone_number_ranges.where(:name => GsParameter.get('SERVICE_NUMBERS')).first.phone_numbers.map{|entry| entry.number}) end end @@ -133,7 +133,7 @@ class Tenant < ActiveRecord::Base end - if STRICT_DID_HANDLING == true + if GsParameter.get('STRICT_DID_HANDLING') == true def array_of_dids_generated_from_did_list numbers = self.did_list.downcase.gsub(/[^0-9,x\+]/,'').gsub(/[,]+/,',').split(/,/) array_of_all_external_numbers = [] @@ -152,7 +152,7 @@ class Tenant < ActiveRecord::Base # Generate the external numbers (DIDs) # def generate_dids - dids = self.phone_number_ranges.find_or_create_by_name(DIRECT_INWARD_DIALING_NUMBERS, :description => 'A list of all available DIDs.') + dids = self.phone_number_ranges.find_or_create_by_name(GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS'), :description => 'A list of all available DIDs.') self.array_of_dids_generated_from_did_list.each do |number| dids.phone_numbers.find_or_create_by_name_and_number('DID', number) end @@ -167,7 +167,7 @@ class Tenant < ActiveRecord::Base @internal_extensions_and_dids ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). where(:phone_numberable_id => self.phone_number_ranges. - where(:name => [INTERNAL_EXTENSIONS, DIRECT_INWARD_DIALING_NUMBERS]). + where(:name => [GsParameter.get('INTERNAL_EXTENSIONS'), GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')]). map{|pnr| pnr.id }) end @@ -175,7 +175,7 @@ class Tenant < ActiveRecord::Base @array_of_internal_extensions ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). where(:phone_numberable_id => self.phone_number_ranges. - where(:name => INTERNAL_EXTENSIONS). + where(:name => GsParameter.get('INTERNAL_EXTENSIONS')). map{|pnr| pnr.id }). map{|phone_number| phone_number.number }. sort.uniq @@ -184,7 +184,7 @@ class Tenant < ActiveRecord::Base def array_of_dids @array_of_dids ||= self.phone_number_ranges_phone_numbers. where(:phone_numberable_type => 'PhoneNumberRange'). - where(:phone_numberable_id => self.phone_number_ranges.where(:name => DIRECT_INWARD_DIALING_NUMBERS).map{|pnr| pnr.id }). + where(:phone_numberable_id => self.phone_number_ranges.where(:name => GsParameter.get('DIRECT_INWARD_DIALING_NUMBERS')).map{|pnr| pnr.id }). map{|phone_number| phone_number.to_s }. sort.uniq end @@ -215,7 +215,7 @@ class Tenant < ActiveRecord::Base # Create a public phone book for this tenant def create_a_default_phone_book - if self.name != SUPER_TENANT_NAME + if self.name != GsParameter.get('SUPER_TENANT_NAME') general_phone_book = self.phone_books.find_or_create_by_name_and_description( I18n.t('phone_books.general_phone_book.name'), I18n.t('phone_books.general_phone_book.description', :resource => self.to_s) diff --git a/app/models/user.rb b/app/models/user.rb index 2d0256f..9b29dc5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -27,7 +27,8 @@ class User < ActiveRecord::Base } validates_length_of [:new_pin, :new_pin_confirmation], - :minimum => MINIMUM_PIN_LENGTH, :maximum => MAXIMUM_PIN_LENGTH, + :minimum => (GsParameter.get('MINIMUM_PIN_LENGTH').nil? ? 4 : GsParameter.get('MINIMUM_PIN_LENGTH')), + :maximum => (GsParameter.get('MAXIMUM_PIN_LENGTH').nil? ? 10 : GsParameter.get('MAXIMUM_PIN_LENGTH')), :allow_blank => true, :allow_nil => true validates_format_of [:new_pin, :new_pin_confirmation], :with => /^[0-9]+$/, |