Merge branch 'master' into domains-nested-refactor

Conflicts:
	config/locales/en.yml
This commit is contained in:
Martin Lensment 2015-03-06 10:26:38 +02:00
commit 08fb2966d4
93 changed files with 2356 additions and 1678 deletions

View file

@ -2,16 +2,31 @@ class Ability
include CanCan::Ability
def initialize(user)
alias_action :create, :read, :update, :destroy, to: :crud
alias_action :show, :create, :update, :destroy, to: :crud
@user = user || AdminUser.new
@user.roles.each { |role| send(role) } if @user.roles
return if @user.roles || @user.roles.any?
case @user.class.to_s
when 'AdminUser'
@user.roles.each { |role| send(role) } if @user.roles
when 'ApiUser'
epp
end
can :show, :dashboard
end
def epp
# Epp::Contact
can(:info, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
can(:check, Epp::Contact)
can(:create, Epp::Contact)
can(:update, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id && c.auth_info == pw }
can(:delete, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id && c.auth_info == pw }
can(:renew, Epp::Contact)
can(:view_password, Epp::Contact) { |c| c.registrar_id == @user.registrar_id }
end
def user
can :show, :dashboard
end
@ -30,6 +45,7 @@ class Ability
can :manage, DomainVersion
can :manage, User
can :manage, ApiUser
can :manage, Certificate
can :manage, Keyrelay
can :manage, LegalDocument
can :read, ApiLog::EppLog

View file

@ -5,14 +5,24 @@ class ApiUser < User
# TODO: should have max request limit per day
belongs_to :registrar
has_many :contacts
has_many :certificates
validates :username, :password, :registrar, presence: true
validates :username, uniqueness: true
before_save :create_crt, if: -> (au) { au.csr_changed? }
attr_accessor :registrar_typeahead
def ability
@ability ||= Ability.new(self)
end
delegate :can?, :cannot?, to: :ability
after_initialize :set_defaults
def set_defaults
return unless new_record?
self.active = true unless active_changed?
end
def registrar_typeahead
@registrar_typeahead || registrar || nil
end
@ -24,28 +34,5 @@ class ApiUser < User
def queued_messages
registrar.messages.queued
end
def create_crt
csr_file = Tempfile.new('client_csr')
csr_file.write(csr)
csr_file.rewind
crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \
-cert #{APP_CONFIG['ca_cert_path']} \
-extensions usr_cert -notext -md sha256 \
-in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch")
if err.match(/Data Base Updated/)
crt_file.rewind
self.crt = crt_file.read
return true
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
logger.error(err)
return false
end
end
end
# rubocop: enable Metrics/ClassLength

View file

@ -32,10 +32,10 @@ class ApiUserDeprecated < ActiveRecord::Base
csr_file.rewind
crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3("openssl ca -keyfile #{APP_CONFIG['ca_key_path']} \
-cert #{APP_CONFIG['ca_cert_path']} \
_out, err, _st = Open3.capture3("openssl ca -keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-extensions usr_cert -notext -md sha256 \
-in #{csr_file.path} -out #{crt_file.path} -key '#{APP_CONFIG['ca_key_password']}' -batch")
-in #{csr_file.path} -out #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/)
crt_file.rewind

88
app/models/certificate.rb Normal file
View file

@ -0,0 +1,88 @@
class Certificate < ActiveRecord::Base
include Versions
belongs_to :api_user
SIGNED = 'signed'
UNSIGNED = 'unsigned'
EXPIRED = 'expired'
REVOKED = 'revoked'
VALID = 'valid'
validates :csr, presence: true
def parsed_crt
@p_crt ||= OpenSSL::X509::Certificate.new(crt) if crt
end
def parsed_csr
@p_csr ||= OpenSSL::X509::Request.new(csr) if csr
end
def revoked?
status == REVOKED
end
def status
return UNSIGNED if crt.blank?
return @cached_status if @cached_status
@cached_status = SIGNED
if parsed_crt.not_before > Time.now.utc && parsed_crt.not_after < Time.now.utc
@cached_status = EXPIRED
end
crl = OpenSSL::X509::CRL.new(File.open(ENV['crl_path']).read)
return @cached_status unless crl.revoked.map(&:serial).include?(parsed_crt.serial)
@cached_status = REVOKED
end
def sign!
csr_file = Tempfile.new('client_csr')
csr_file.write(csr)
csr_file.rewind
crt_file = Tempfile.new('client_crt')
_out, err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-extensions usr_cert -notext -md sha256 \
-in #{csr_file.path} -out #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/)
crt_file.rewind
self.crt = crt_file.read
save!
else
errors.add(:base, I18n.t('failed_to_create_certificate'))
logger.error('FAILED TO CREATE CLIENT CERTIFICATE')
logger.error(err)
return false
end
end
def revoke!
crt_file = Tempfile.new('client_crt')
crt_file.write(crt)
crt_file.rewind
_out, err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch")
if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/)
save!
@cached_status = REVOKED
else
errors.add(:base, I18n.t('failed_to_revoke_certificate'))
logger.error('FAILED TO REVOKE CLIENT CERTIFICATE')
logger.error(err)
return false
end
_out, _err, _st = Open3.capture3("openssl ca -config #{ENV['openssl_config_path']} -keyfile #{ENV['ca_key_path']} \
-cert #{ENV['ca_cert_path']} \
-gencrl -out #{ENV['crl_path']} -key '#{ENV['ca_key_password']}' -batch")
end
end

View file

@ -3,42 +3,43 @@ module EppErrors
def construct_epp_errors
epp_errors = []
errors.messages.each do |key, values|
key = key.to_s.split('.')[0].to_sym
next if key == :epp_errors
errors.messages.each do |attr, errors|
attr = attr.to_s.split('.')[0].to_sym
next if attr == :epp_errors
if self.class.reflect_on_association(key)
epp_errors << collect_child_errors(key)
if self.class.reflect_on_association(attr)
epp_errors << collect_child_errors(attr)
end
epp_errors << collect_parent_errors(values)
epp_errors << collect_parent_errors(attr, errors)
end
errors[:epp_errors] = epp_errors
errors[:epp_errors].flatten!
end
def collect_parent_errors(values)
epp_errors = []
values = [values] if values.is_a?(String)
def collect_parent_errors(attr, errors)
errors = [errors] if errors.is_a?(String)
values.each do |err|
epp_errors = []
errors.each do |err|
code, value = find_epp_code_and_value(err)
next unless code
epp_errors << { code: code, msg: err, value: value }
msg = attr.to_sym == :base ? err : "#{err} [#{attr}]"
epp_errors << { code: code, msg: msg, value: value }
end
epp_errors
end
def collect_child_errors(key)
macro = self.class.reflect_on_association(key).macro
def collect_child_errors(attr)
macro = self.class.reflect_on_association(attr).macro
multi = [:has_and_belongs_to_many, :has_many]
# single = [:belongs_to, :has_one]
epp_errors = []
send(key).each do |x|
x.errors.messages.each do |_key, values|
epp_errors << x.collect_parent_errors(values)
send(attr).each do |x|
x.errors.messages.each do |attribute, errors|
epp_errors << x.collect_parent_errors(attribute, errors)
end
end if multi.include?(macro)

View file

@ -5,7 +5,7 @@ module VersionSession
before_save :add_session
def add_session
self.session = PaperSession.session
self.session = ::PaperSession.session
true
end
end

View file

@ -28,9 +28,9 @@ module Versions
return nil if creator_str.blank?
if creator_str =~ /^\d-api-/
ApiUser.find(creator_str)
ApiUser.find_by(id: creator_str)
else
AdminUser.find(creator_str)
AdminUser.find_by(id: creator_str)
end
end
@ -38,9 +38,9 @@ module Versions
return nil if updator_str.blank?
if updator_str =~ /^\d-api-/
ApiUser.find(updator_str)
ApiUser.find_by(id: updator_str)
else
AdminUser.find(updator_str)
AdminUser.find_by(id: updator_str)
end
end

View file

@ -1,6 +1,5 @@
class Contact < ActiveRecord::Base
include Versions # version/contact_version.rb
include EppErrors
has_one :address, dependent: :destroy
has_one :disclosure, class_name: 'ContactDisclosure', dependent: :destroy
@ -8,45 +7,46 @@ class Contact < ActiveRecord::Base
has_many :domain_contacts
has_many :domains, through: :domain_contacts
has_many :statuses, class_name: 'ContactStatus'
has_many :legal_documents, as: :documentable
belongs_to :registrar
accepts_nested_attributes_for :address, :disclosure
accepts_nested_attributes_for :address, :disclosure, :legal_documents
validates :name, :phone, :email, :ident, :address, :registrar, :ident_type, presence: true
# Phone nr validation is very minimam in order to support legacy requirements
validates :phone, format: /\+[0-9]{1,3}\.[0-9]{1,14}?/
validates :email, format: /@/
validates :ident, format: /\d{4}-\d{2}-\d{2}/, if: proc { |c| c.ident_type == 'birthday' }
validates :ident,
format: { with: /\d{4}-\d{2}-\d{2}/, message: :invalid_birthday_format },
if: proc { |c| c.ident_type == 'birthday' }
validates :ident_country_code, presence: true, if: proc { |c| %w(bic priv).include? c.ident_type }
validates :code,
uniqueness: { message: :epp_id_taken },
format: { with: /\A[\w\-\:]*\Z/i },
length: { maximum: 100 }
validate :ident_must_be_valid
validate :ident_valid_format?
validates :code, uniqueness: { message: :epp_id_taken }
delegate :street, to: :address
delegate :city, to: :address
delegate :zip, to: :address
delegate :state, to: :address
delegate :country_code, to: :address
delegate :country, to: :address
delegate :city, to: :address # , prefix: true
delegate :street, to: :address # , prefix: true
delegate :zip, to: :address # , prefix: true
# callbacks
# TODO: remove old
# after_commit :domains_snapshot
# after_update :domains_snapshot
# after_destroy :domains_snapshot
before_validation :set_ident_country_code
before_create :generate_code
before_create :generate_auth_info
after_create :ensure_disclosure
# scopes
scope :current_registrars, ->(id) { where(registrar_id: id) }
IDENT_TYPE_ICO = 'ico'
IDENT_TYPE_BIC = 'bic'
IDENT_TYPES = [
IDENT_TYPE_ICO, # Company registry code (or similar)
'bic', # Business registry code
IDENT_TYPE_BIC, # Company registry code (or similar)
'priv', # National idendtification number
'op', # Estonian ID, depricated
'passport', # Passport number, depricated
'birthday' # Birthday date
]
@ -54,124 +54,10 @@ class Contact < ActiveRecord::Base
CONTACT_TYPE_ADMIN = 'admin'
CONTACT_TYPES = [CONTACT_TYPE_TECH, CONTACT_TYPE_ADMIN]
def ident_must_be_valid
# TODO: Ident can also be passport number or company registry code.
# so have to make changes to validations (and doc/schema) accordingly
return true unless ident.present? && ident_type.present? && ident_type == 'op'
code = Isikukood.new(ident)
errors.add(:ident, 'bad format') unless code.valid?
end
def ensure_disclosure
create_disclosure! unless disclosure
end
# TODO: remove old
# def domains_snapshot
# (domains + domains_owned).uniq.each do |domain|
# next unless domain.is_a?(Domain)
# # next if domain.versions.last == domain.create_snapshot
# domain.create_version # Method from paper_trail
# end
# end
def juridical?
ident_type == IDENT_TYPE_ICO
end
def citizen?
ident_type != IDENT_TYPE_ICO
end
def cr_id
# created_by ? created_by.username : nil
end
def up_id
# updated_by ? updated_by.username : nil
end
def auth_info_matches(pw)
auth_info == pw
end
# generate random id for contact
def generate_code
self.code = SecureRandom.hex(4)
end
def generate_auth_info
self.auth_info = SecureRandom.hex(16)
end
# Find a way to use self.domains with contact
def domains_owned
Domain.where(owner_contact_id: id)
end
def relations_with_domain?
return true if domain_contacts.present? || domains_owned.present?
false
end
# should use only in transaction
def destroy_and_clean
if relations_with_domain?
errors.add(:domains, :exist)
return false
end
destroy
end
def epp_code_map # rubocop:disable Metrics/MethodLength
{
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2305' => [ # Association exists
[:domains, :exist]
],
'2005' => [ # Value syntax error
[:phone, :invalid],
[:email, :invalid],
[:ident, :invalid]
]
}
end
def to_s
name
end
# TODO: remove old
# for archiving
# def snapshot
# {
# name: name,
# phone: phone,
# code: code,
# ident: ident,
# email: email
# }
# end
class << self
# non-EPP
# EPP
def extract_attributes(ph, _type = :create)
ph[:postalInfo] = ph[:postalInfo].first if ph[:postalInfo].is_a?(Array)
contact_hash = {
phone: ph[:voice],
ident: ph[:ident],
ident_type: ph[:ident_type],
email: ph[:email],
fax: ph[:fax],
name: ph[:postalInfo].try(:[], :name),
org_name: ph[:postalInfo].try(:[], :org)
}
# contact_hash[:auth_info] = ph[:authInfo][:pw] if type == :create
contact_hash.delete_if { |_k, v| v.nil? }
def search_by_query(query)
res = search(code_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v.name} (#{v.code})" } }
end
def check_availability(codes)
@ -188,10 +74,84 @@ class Contact < ActiveRecord::Base
res
end
end
def search_by_query(query)
res = search(code_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v.name} (#{v.code})" } }
def to_s
name
end
def ident_valid_format?
case ident_type
when 'priv'
case ident_country_code
when 'EE'
code = Isikukood.new(ident)
errors.add(:ident, :invalid_EE_identity_format) unless code.valid?
end
end
end
def ensure_disclosure
create_disclosure! unless disclosure
end
def bic?
ident_type == IDENT_TYPE_BIC
end
def priv?
ident_type != IDENT_TYPE_BIC
end
def generate_code
self.code = SecureRandom.hex(4) if code.blank?
end
def generate_auth_info
return if @generate_auth_info_disabled
self.auth_info = SecureRandom.hex(16)
end
def disable_generate_auth_info! # needed for testing
@generate_auth_info_disabled = true
end
def auth_info=(pw)
self[:auth_info] = pw if new_record?
end
def code=(code)
self[:code] = code if new_record?
end
# Find a way to use self.domains with contact
def domains_owned
Domain.where(owner_contact_id: id)
end
def relations_with_domain?
return true if domain_contacts.present? || domains_owned.present?
false
end
# TODO: refactor, it should not allow to destroy with normal destroy,
# no need separate method
# should use only in transaction
def destroy_and_clean
if relations_with_domain?
errors.add(:domains, :exist)
return false
end
destroy
end
def set_ident_country_code
return true unless ident_country_code_changed? && ident_country_code.present?
code = Country.new(ident_country_code)
if code
self.ident_country_code = code.alpha2
else
errors.add(:ident_country_code, 'is not following ISO_3166-1 alpha 2 format')
end
end
end

View file

@ -85,9 +85,9 @@ class Dnskey < ActiveRecord::Base
end
def generate_ds_key_tag
public_key.gsub!(' ', '')
pk = public_key.gsub(' ', '')
wire_format = [flags, protocol, alg].pack('S!>CC')
wire_format += Base64.decode64(public_key)
wire_format += Base64.decode64(pk)
c = 0
wire_format.each_byte.with_index do |b, i|

View file

@ -20,8 +20,6 @@ class Domain < ActiveRecord::Base
-> { where(domain_contacts: { contact_type: DomainContact::ADMIN }) },
through: :domain_contacts, source: :contact
# TODO: remove old
# has_many :nameservers, dependent: :delete_all, after_add: :track_nameserver_add
has_many :nameservers, dependent: :delete_all
accepts_nested_attributes_for :nameservers, allow_destroy: true,
@ -43,11 +41,11 @@ class Domain < ActiveRecord::Base
has_many :legal_documents, as: :documentable
accepts_nested_attributes_for :legal_documents, reject_if: proc { |attrs| attrs[:body].blank? }
delegate :code, to: :owner_contact, prefix: true
delegate :code, to: :owner_contact, prefix: true
delegate :email, to: :owner_contact, prefix: true
delegate :ident, to: :owner_contact, prefix: true
delegate :phone, to: :owner_contact, prefix: true
delegate :name, to: :registrar, prefix: true
delegate :name, to: :registrar, prefix: true
before_create :generate_auth_info
before_create :set_validity_dates
@ -118,11 +116,6 @@ class Domain < ActiveRecord::Base
attr_accessor :owner_contact_typeahead, :update_me
# TODO: remove old
# archiving
# if proc works only on changes on domain sadly
# has_paper_trail class_name: 'DomainVersion', meta: { snapshot: :create_snapshot }, if: proc(&:new_version)
def tech_domain_contacts
domain_contacts.select { |x| x.contact_type == DomainContact::TECH }
end
@ -131,52 +124,6 @@ class Domain < ActiveRecord::Base
domain_contacts.select { |x| x.contact_type == DomainContact::ADMIN }
end
# TODO: remove old
# def new_version
# return false if versions.try(:last).try(:snapshot) == create_snapshot
# true
# end
# TODO: remove old
# def create_version
# return true unless PaperTrail.enabled?
# return true unless valid?
# touch_with_version if new_version
# end
# TODO: remove old
# def track_nameserver_add(_nameserver)
# return true if versions.count == 0
# return true unless valid? && new_version
# touch_with_version
# end
# TODO: remove old
# def create_snapshot
# oc = owner_contact.snapshot if owner_contact.is_a?(Contact)
# {
# owner_contact: oc,
# tech_contacts: tech_contacts.map(&:snapshot),
# admin_contacts: admin_contacts.map(&:snapshot),
# nameservers: nameservers.map(&:snapshot),
# domain: make_snapshot
# }.to_yaml
# end
# TODO: remove old
# def make_snapshot
# {
# name: name,
# status: status,
# period: period,
# period_unit: period_unit,
# registrar_id: registrar.try(:id),
# valid_to: valid_to,
# valid_from: valid_from
# }
# end
def name=(value)
value.strip!
value.downcase!
@ -265,7 +212,7 @@ class Domain < ActiveRecord::Base
attach_contact(DomainContact::TECH, owner_contact)
end
return unless admin_domain_contacts.count.zero? && owner_contact.citizen?
return unless admin_domain_contacts.count.zero? && owner_contact.priv?
attach_contact(DomainContact::ADMIN, owner_contact)
end
@ -305,36 +252,36 @@ class Domain < ActiveRecord::Base
# rubocop:disable Metrics/MethodLength
def update_whois_body
self.whois_body = <<-EOS
This Whois Server contains information on
Estonian Top Level Domain ee TLD
This Whois Server contains information on
Estonian Top Level Domain ee TLD
domain: #{name}
registrar: #{registrar}
status:
registered:
changed: #{updated_at.to_s(:db)}
expire:
outzone:
delete:
domain: #{name}
registrar: #{registrar}
status:
registered:
changed: #{updated_at.to_s(:db)}
expire:
outzone:
delete:
contact
name:
e-mail:
registrar:
created:
contact
name:
e-mail:
registrar:
created:
contact:
contact:
nsset:
nserver:
nsset:
nserver:
registrar:
org:
url:
phone:
address:
created:
changed:
registrar:
org:
url:
phone:
address:
created:
changed:
EOS
end
# rubocop:enabled Metrics/MethodLength

102
app/models/epp/contact.rb Normal file
View file

@ -0,0 +1,102 @@
# rubocop: disable Metrics/ClassLength
class Epp::Contact < Contact
include EppErrors
# disable STI, there is type column present
self.inheritance_column = :sti_disabled
class << self
# rubocop: disable Metrics/PerceivedComplexity
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/MethodLength
def attrs_from(frame)
f = frame
at = {}.with_indifferent_access
at[:name] = f.css('postalInfo name').text if f.css('postalInfo name').present?
at[:org_name] = f.css('postalInfo org').text if f.css('postalInfo org').present?
at[:email] = f.css('email').text if f.css('email').present?
at[:fax] = f.css('fax').text if f.css('fax').present?
at[:phone] = f.css('voice').text if f.css('voice').present?
at[:auth_info] = f.css('authInfo pw').text if f.css('authInfo pw').present?
if f.css('ident').present? && f.css('ident').attr('type').present?
at[:ident] = f.css('ident').text
at[:ident_type] = f.css('ident').attr('type').try(:text)
at[:ident_country_code] = f.css('ident').attr('cc').try(:text)
end
at[:address_attributes] = {}.with_indifferent_access
sat = at[:address_attributes]
sat[:city] = f.css('postalInfo addr city').text if f.css('postalInfo addr city').present?
sat[:zip] = f.css('postalInfo addr pc').text if f.css('postalInfo addr pc').present?
sat[:street] = f.css('postalInfo addr street').text if f.css('postalInfo addr street').present?
sat[:state] = f.css('postalInfo addr sp').text if f.css('postalInfo addr sp').present?
sat[:country_code] = f.css('postalInfo addr cc').text if f.css('postalInfo addr cc').present?
at.delete(:address_attributes) if at[:address_attributes].blank?
legal_frame = f.css('legalDocument').first
if legal_frame.present?
at[:legal_documents_attributes] = legal_document_attrs(legal_frame)
end
at
end
# rubocop: enable Metrics/MethodLength
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
def new(frame, registrar)
return super if frame.blank?
custom_code =
if frame.css('id').present?
"#{registrar.code}:#{frame.css('id').text.parameterize}"
else
nil
end
super(
attrs_from(frame).merge(
code: custom_code,
registrar: registrar
)
)
end
def legal_document_attrs(legal_frame)
[{
body: legal_frame.text,
document_type: legal_frame['type']
}]
end
end
def epp_code_map # rubocop:disable Metrics/MethodLength
{
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2305' => [ # Association exists
[:domains, :exist]
],
'2005' => [ # Value syntax error
[:phone, :invalid],
[:email, :invalid],
[:ident, :invalid],
[:ident, :invalid_EE_identity_format],
[:ident, :invalid_birthday_format]
]
}
end
def update_attributes(frame)
return super if frame.blank?
at = {}.with_indifferent_access
at.deep_merge!(self.class.attrs_from(frame.css('chg')))
legal_frame = frame.css('legalDocument').first
at[:legal_documents_attributes] = self.class.legal_document_attrs(legal_frame)
super(at)
end
end
# rubocop: enable Metrics/ClassLength

View file

@ -146,7 +146,7 @@ class Epp::EppDomain < Domain
next
end
if k == :admin && contact.juridical?
if k == :admin && contact.bic?
add_epp_error('2306', 'contact', x[:contact], [:domain_contacts, :admin_contact_can_be_only_citizen])
next
end

View file

@ -9,10 +9,18 @@ class Registrar < ActiveRecord::Base
validates :name, :reg_no, :country_code, :email, presence: true
validates :name, :reg_no, uniqueness: true
validate :set_code, if: :new_record?
after_save :touch_domains_version
validates :email, :billing_email, format: /@/, allow_blank: true
class << self
def search_by_query(query)
res = search(name_or_reg_no_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } }
end
end
def domain_transfers
at = DomainTransfer.arel_table
DomainTransfer.where(
@ -23,7 +31,7 @@ class Registrar < ActiveRecord::Base
end
def address
[street, city, state, zip].reject(&:empty?).compact.join(', ')
[street, city, state, zip].reject(&:blank?).compact.join(', ')
end
def to_s
@ -34,10 +42,23 @@ class Registrar < ActiveRecord::Base
Country.new(country_code)
end
class << self
def search_by_query(query)
res = search(name_or_reg_no_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } }
def code=(code)
self[:code] = code if new_record?
end
private
def set_code
return false if name.blank?
new_code = name.parameterize
# ensure code is always uniq automatically for a new record
seq = 1
while self.class.find_by_code(new_code)
new_code += seq.to_s
seq += 1
end
self.code = new_code
end
end

View file

@ -0,0 +1,4 @@
class CertificateVersion < PaperTrail::Version
self.table_name = :log_certificates
self.sequence_name = :log_certificates_id_seq
end

View file

@ -18,7 +18,7 @@ class ZonefileSetting < ActiveRecord::Base
"select generate_zonefile('#{origin}')"
)[0]['generate_zonefile']
File.open("#{APP_CONFIG['zonefile_export_dir']}/#{filename}", 'w') { |f| f.write(zf) }
File.open("#{ENV['zonefile_export_dir']}/#{filename}", 'w') { |f| f.write(zf) }
STDOUT << "#{Time.now.utc} - Successfully generated zonefile #{filename}\n"
end