mirror of
https://github.com/internetee/registry.git
synced 2025-07-31 06:56:23 +02:00
Removed and updated additional files
This commit is contained in:
parent
11c2af075a
commit
04b55068df
29 changed files with 154 additions and 1534 deletions
|
@ -1,227 +0,0 @@
|
|||
class Registrar
|
||||
class DomainsController < DeppController
|
||||
before_action :init_domain, except: :new
|
||||
helper_method :contacts
|
||||
helper_method :search_params
|
||||
|
||||
def index
|
||||
authorize! :view, Depp::Domain
|
||||
|
||||
if search_params.to_h.delete_if { |_key, value| value.blank? }.length == 1 &&
|
||||
search_params[:name_matches].present?
|
||||
domain = Domain.find_by(name: search_params[:name_matches])
|
||||
|
||||
redirect_to info_registrar_domains_url(domain_name: domain.name) and return if domain
|
||||
end
|
||||
|
||||
domains = if params[:statuses_contains]
|
||||
current_domain_scope.where('domains.statuses @> ?::varchar[]',
|
||||
"{#{params[:statuses_contains].join(',')}}")
|
||||
else
|
||||
current_domain_scope
|
||||
end
|
||||
|
||||
domains = domains.where(contacts: { ident: params[:contacts_ident_eq] }) if params[:contacts_ident_eq]
|
||||
|
||||
normalize_search_parameters do
|
||||
@q = domains.ransack(search_params.except(:contacts_ident_eq))
|
||||
@domains = @q.result.page(params[:page])
|
||||
|
||||
# if we do not get any results, add wildcards to the name field and search again
|
||||
if @domains.count == 0 && search_params[:name_matches] !~ /^%.+%$/
|
||||
new_search_params = search_params.to_h.except(:contacts_ident_eq)
|
||||
new_search_params[:name_matches] = "%#{new_search_params[:name_matches]}%"
|
||||
@q = domains.ransack(new_search_params)
|
||||
@domains = @q.result.page(params[:page])
|
||||
end
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.csv do
|
||||
domain_presenters = []
|
||||
|
||||
@q.result.find_each do |domain|
|
||||
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
|
||||
end
|
||||
|
||||
raw_csv = Registrar::DomainListCsvPresenter.new(domains: domain_presenters,
|
||||
view: view_context).to_s
|
||||
filename = "Domains_#{l(Time.zone.now, format: :filename)}.csv"
|
||||
send_data raw_csv, filename: filename, type: "#{Mime[:csv]}; charset=utf-8"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def current_domain_scope
|
||||
current_registrar_user.registrar.domains.includes(:registrar, :registrant)
|
||||
end
|
||||
|
||||
def info
|
||||
authorize! :info, Depp::Domain
|
||||
@data = @domain.info(params[:domain_name]) if params[:domain_name]
|
||||
@pending_delete = domain_delete_pending(@data)
|
||||
@client_holded = client_holded(@data)
|
||||
if response_ok?
|
||||
render 'info'
|
||||
else
|
||||
flash[:alert] = @data.css('msg').text
|
||||
redirect_to registrar_domains_url and return
|
||||
end
|
||||
end
|
||||
|
||||
def check
|
||||
authorize! :check, Depp::Domain
|
||||
if params[:domain_name]
|
||||
@data = @domain.check(params[:domain_name])
|
||||
render 'check_index' and return unless response_ok?
|
||||
else
|
||||
render 'check_index'
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
authorize! :create, Depp::Domain
|
||||
@domain_params = Depp::Domain.default_params
|
||||
@domain_params[:period] = Depp::Domain.default_period
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/CognitiveComplexity
|
||||
def create
|
||||
authorize! :create, Depp::Domain
|
||||
@domain_params = domain_params.to_h
|
||||
@data = @domain.create(@domain_params)
|
||||
|
||||
if @data && response_ok?
|
||||
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
||||
else
|
||||
flash[:alert] = t('.email_error_message') unless @emails_check_result
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
authorize! :update, Depp::Domain
|
||||
@data = @domain.info(params[:domain_name])
|
||||
@domain_params = Depp::Domain.construct_params_from_server_data(@data)
|
||||
@dispute = Dispute.active.find_by(domain_name: params[:domain_name])
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Depp::Domain
|
||||
@domain_params = params[:domain]
|
||||
@data = @domain.update(@domain_params)
|
||||
@dispute = Dispute.active.find_by(domain_name: @domain_params[:name])
|
||||
|
||||
if @data && response_ok?
|
||||
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
||||
else
|
||||
flash[:alert] = t('.email_error_message') unless @emails_check_result
|
||||
params[:domain_name] = @domain_params[:name]
|
||||
render 'new'
|
||||
end
|
||||
end
|
||||
# rubocop:enable Metrics/CognitiveComplexity
|
||||
|
||||
def delete
|
||||
authorize! :delete, Depp::Domain
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Depp::Domain
|
||||
@data = @domain.delete(params[:domain])
|
||||
@results = @data.css('result')
|
||||
if response_ok?
|
||||
flash[:notice] = t('.deleting_request')
|
||||
redirect_to info_registrar_domains_url(domain_name: params[:domain][:name])
|
||||
else
|
||||
params[:domain_name] = params[:domain][:name]
|
||||
render 'delete'
|
||||
end
|
||||
end
|
||||
|
||||
def renew
|
||||
authorize! :renew, Depp::Domain
|
||||
if params[:domain_name] && params[:cur_exp_date]
|
||||
@data = @domain.renew(params)
|
||||
render 'renew_index' and return unless response_ok?
|
||||
else
|
||||
params[:period] = Depp::Domain.default_period
|
||||
render 'renew_index'
|
||||
end
|
||||
end
|
||||
|
||||
def search_contacts
|
||||
authorize! :create, Depp::Domain
|
||||
|
||||
scope = current_registrar_user.registrar.contacts.limit(10)
|
||||
if params[:query].present?
|
||||
escaped_str = ActiveRecord::Base.connection.quote_string params[:query]
|
||||
scope = scope.where("name ilike '%#{escaped_str}%' OR code ilike '%#{escaped_str}%' ")
|
||||
end
|
||||
|
||||
render json: scope.pluck(:name, :code).map { |c| { display_key: "#{c.second} #{c.first}", value: c.second } }
|
||||
end
|
||||
|
||||
def remove_hold
|
||||
authorize! :remove_hold, Depp::Domain
|
||||
return unless params[:domain_name]
|
||||
|
||||
@data = @domain.remove_hold(params)
|
||||
|
||||
flash[:alert] = @data.css('msg').text unless response_ok?
|
||||
redirect_to info_registrar_domains_url(domain_name: params[:domain_name])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def init_domain
|
||||
@domain = Depp::Domain.new(current_user: depp_current_user)
|
||||
end
|
||||
|
||||
def client_holded(data)
|
||||
data.css('status')&.map { |element| element.attribute('s').value }
|
||||
&.any? { |status| status == DomainStatus::CLIENT_HOLD }
|
||||
end
|
||||
|
||||
def domain_delete_pending(data)
|
||||
data.css('status')&.map { |element| element.attribute('s').value }
|
||||
&.any? { |status| status.include?(DomainStatus::PENDING_DELETE) }
|
||||
end
|
||||
|
||||
def contacts
|
||||
current_registrar_user.registrar.contacts
|
||||
end
|
||||
|
||||
def normalize_search_parameters
|
||||
ca_cache = search_params[:valid_to_lteq]
|
||||
begin
|
||||
end_time = search_params[:valid_to_lteq].try(:to_date)
|
||||
search_params[:valid_to_lteq] = end_time.try(:end_of_day)
|
||||
rescue
|
||||
logger.warn('Invalid date')
|
||||
end
|
||||
|
||||
yield
|
||||
|
||||
search_params[:valid_to_lteq] = ca_cache
|
||||
end
|
||||
|
||||
def search_params
|
||||
params.fetch(:q, {}).permit(:name_matches,
|
||||
:registrant_ident_eq,
|
||||
:contacts_ident_eq,
|
||||
:nameservers_hostname_eq,
|
||||
:valid_to_gteq,
|
||||
:valid_to_lteq,
|
||||
:s)
|
||||
end
|
||||
|
||||
def domain_params
|
||||
params.require(:domain).permit(:name, :period, :registrant, :registrant_helper, :reserved_pw,
|
||||
:verified, :legal_document, contacts_attributes: {},
|
||||
nameservers_attributes: {},
|
||||
dnskeys_attributes: {})
|
||||
end
|
||||
end
|
||||
end
|
|
@ -43,7 +43,7 @@ module Repp
|
|||
|
||||
def validate_renew_period
|
||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||
periods = Depp::Domain::PERIODS.map { |p| p[1] }
|
||||
periods = Domain::PERIODS.map { |p| p[1] }
|
||||
return if periods.include? bulk_renew_params[:renew_period]
|
||||
|
||||
@epp_errors.add(:epp_errors, msg: 'Invalid renew period', code: '2005')
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
module Registrar::ApplicationHelper
|
||||
def env_style
|
||||
return '' if unstable_env.nil?
|
||||
"background-image: url(#{image_path("registrar/bg-#{unstable_env}.png")});"
|
||||
end
|
||||
end
|
|
@ -32,9 +32,7 @@ class Ability
|
|||
|
||||
def epp # Registrar/api_user dynamic role
|
||||
if @user.registrar.api_ip_white?(@ip)
|
||||
can :manage, Depp::Contact
|
||||
can :manage, :xml_console
|
||||
can :manage, Depp::Domain
|
||||
end
|
||||
|
||||
can :manage, Account
|
||||
|
@ -122,7 +120,6 @@ class Ability
|
|||
customer_service
|
||||
can :manage, :registrant_domains
|
||||
can :manage, :registrant_whois
|
||||
can :manage, Depp::Domain
|
||||
can :manage, Domain
|
||||
end
|
||||
|
||||
|
|
|
@ -1,318 +0,0 @@
|
|||
module Depp
|
||||
class Contact
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :id, :name, :email, :phone, :org_name,
|
||||
:ident, :ident_type, :ident_country_code,
|
||||
:street, :city, :zip, :state, :country_code,
|
||||
:password, :legal_document, :statuses, :code,
|
||||
:email_history
|
||||
|
||||
DISABLED = 'Disabled'
|
||||
DISCLOSURE_TYPES = [DISABLED, '1', '0']
|
||||
TYPES = %w( org priv birthday )
|
||||
SELECTION_TYPES = [
|
||||
['Business code', 'org'],
|
||||
['Personal identification code', 'priv'],
|
||||
['Birthday', 'birthday']
|
||||
]
|
||||
|
||||
validates :phone, e164: true, phone: true
|
||||
|
||||
class << self
|
||||
attr_reader :epp_xml, :user
|
||||
|
||||
def new_from_params(params)
|
||||
new(
|
||||
id: params[:code],
|
||||
code: params[:code],
|
||||
email: params[:email],
|
||||
phone: params[:phone],
|
||||
ident: params[:ident],
|
||||
ident_type: params[:ident_type],
|
||||
ident_country_code: params[:ident_country_code],
|
||||
|
||||
# postalInfo
|
||||
name: params[:name],
|
||||
org_name: params[:org_name],
|
||||
|
||||
# address
|
||||
street: params[:street],
|
||||
city: params[:city],
|
||||
zip: params[:zip],
|
||||
state: params[:state],
|
||||
country_code: params[:country_code]
|
||||
)
|
||||
end
|
||||
|
||||
def find_by_id(id)
|
||||
data = info_xml(id)
|
||||
|
||||
res = data.css('epp response resData infData')
|
||||
ext = data.css('epp response extension')
|
||||
new(
|
||||
id: res.css('id').text,
|
||||
code: res.css('id').text,
|
||||
email: res.css('email').text,
|
||||
phone: res.css('voice').text,
|
||||
ident: ext.css('ident').text,
|
||||
ident_type: ext.css('ident').first.try(:attributes).try(:[], 'type').try(:value),
|
||||
ident_country_code: ext.css('ident').first.try(:attributes).try(:[], 'cc').try(:value),
|
||||
|
||||
# postalInfo
|
||||
name: res.css('postalInfo name').text,
|
||||
org_name: res.css('postalInfo org').text,
|
||||
|
||||
# address
|
||||
street: res.css('postalInfo addr street').text,
|
||||
city: res.css('postalInfo addr city').text,
|
||||
zip: res.css('postalInfo addr pc').text,
|
||||
state: res.css('postalInfo addr sp').text,
|
||||
country_code: res.css('postalInfo addr cc').text,
|
||||
|
||||
# authInfo
|
||||
password: res.css('authInfo pw').text,
|
||||
|
||||
# statuses
|
||||
statuses: data.css('status').map { |s| [s['s'], s.text] }
|
||||
)
|
||||
end
|
||||
|
||||
def user=(user)
|
||||
@user = user
|
||||
@epp_xml = EppXml::Contact.new(cl_trid_prefix: user.tag, schema_prefix: 'contact-ee',
|
||||
schema_version: '1.1')
|
||||
end
|
||||
|
||||
def info_xml(id, password = nil)
|
||||
xml = epp_xml.info(
|
||||
id: { value: id },
|
||||
authInfo: { pw: { value: password } }
|
||||
)
|
||||
user.request(xml)
|
||||
end
|
||||
|
||||
def construct_check_hash_from_data(data)
|
||||
res = data.css('epp response resData chkData cd')
|
||||
@contacts = []
|
||||
res.each do |_r|
|
||||
id = res.css('id').try(:text)
|
||||
reason = res.css('reason').present? ? res.css('reason').text : I18n.t(:available)
|
||||
@contacts << { id: id, reason: reason }
|
||||
end
|
||||
@contacts
|
||||
end
|
||||
|
||||
def contact_id_from_xml(data)
|
||||
id = data.css('epp response resData creData id').text
|
||||
id.blank? ? nil : id
|
||||
end
|
||||
|
||||
def construct_create_disclosure_xml(cph, flag)
|
||||
xml = { disclose: {} }
|
||||
cph.each do |k, v|
|
||||
xml[:disclose][k] = {}
|
||||
xml[:disclose][k][:value] = v
|
||||
end
|
||||
xml[:disclose][:attrs] = {}
|
||||
xml[:disclose][:attrs][:flag] = flag
|
||||
xml.with_indifferent_access
|
||||
end
|
||||
|
||||
# cpd = contact_params[:disclose]
|
||||
def extract_disclosure_hash(cpd)
|
||||
return {} unless cpd
|
||||
|
||||
cpd.delete_if { |k, v| v if v != '1' && k == 'flag' }
|
||||
end
|
||||
|
||||
def extract_info_disclosure(data)
|
||||
hash = {}
|
||||
data.css('disclose').each do |d|
|
||||
flag = d.attributes['flag'].value
|
||||
next unless flag
|
||||
hash[flag] = {}
|
||||
d.children.each do |c|
|
||||
hash[flag][c.name] = flag if %w( name email fax voice addr org_name ).include?(c.name)
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def type_string(type_code)
|
||||
return '' if type_code.blank?
|
||||
t = SELECTION_TYPES.select { |tp| tp.second == type_code }
|
||||
t.try(:first).try(:first)
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
return false unless valid?
|
||||
|
||||
hash = {
|
||||
id: { value: code },
|
||||
postalInfo: {
|
||||
name: { value: name },
|
||||
org: { value: org_name },
|
||||
},
|
||||
voice: { value: phone },
|
||||
email: { value: email }
|
||||
}
|
||||
|
||||
if ::Contact.address_processing?
|
||||
hash[:postalInfo][:addr] = {
|
||||
street: { value: street },
|
||||
city: { value: city },
|
||||
sp: { value: state },
|
||||
pc: { value: zip },
|
||||
cc: { value: country_code },
|
||||
}
|
||||
end
|
||||
|
||||
hash[:id] = nil if code.blank?
|
||||
create_xml = Depp::Contact.epp_xml.create(hash, extension_xml(:create))
|
||||
data = Depp::Contact.user.request(create_xml)
|
||||
self.id = data.css('id').text
|
||||
handle_errors(data)
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/MethodLength
|
||||
def update_attributes(params)
|
||||
return false unless valid?
|
||||
|
||||
self.ident_country_code = params[:ident_country_code]
|
||||
self.ident_type = params[:ident_type]
|
||||
self.ident = params[:ident]
|
||||
|
||||
self.name = params[:name]
|
||||
self.email = params[:email]
|
||||
self.phone = params[:phone]
|
||||
|
||||
self.org_name = params[:org_name]
|
||||
|
||||
if ::Contact.address_processing?
|
||||
self.street = params[:street]
|
||||
self.city = params[:city]
|
||||
self.zip = params[:zip]
|
||||
self.state = params[:state]
|
||||
self.country_code = params[:country_code]
|
||||
end
|
||||
|
||||
attributes = {
|
||||
id: { value: id },
|
||||
chg: {
|
||||
postalInfo: {
|
||||
name: { value: name },
|
||||
org: { value: org_name },
|
||||
},
|
||||
voice: { value: phone },
|
||||
email: { value: email },
|
||||
authInfo: {
|
||||
pw: { value: password }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ::Contact.address_processing?
|
||||
attributes[:chg][:postalInfo][:addr] = {
|
||||
street: { value: street },
|
||||
city: { value: city },
|
||||
sp: { value: state },
|
||||
pc: { value: zip },
|
||||
cc: { value: country_code }
|
||||
}
|
||||
end
|
||||
|
||||
update_xml = Depp::Contact.epp_xml.update(attributes, extension_xml(:update))
|
||||
data = Depp::Contact.user.request(update_xml)
|
||||
handle_errors(data)
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
||||
def delete
|
||||
delete_xml = Contact.epp_xml.delete(
|
||||
{
|
||||
id: { value: id },
|
||||
authInfo: { pw: { value: password } }
|
||||
},
|
||||
extension_xml(:delete)
|
||||
)
|
||||
data = Depp::Contact.user.request(delete_xml)
|
||||
handle_errors(data)
|
||||
end
|
||||
|
||||
def extension_xml(action)
|
||||
xml = { _anonymus: [] }
|
||||
|
||||
case action
|
||||
when :create
|
||||
ident = ident_xml[:_anonymus].try(:first)
|
||||
when :update
|
||||
# detect if any ident has changed, nb! ident and self.ident is not always same
|
||||
unless ident == self.ident && ident == ident_type && ident_country_code == self.ident_country_code
|
||||
ident = ident_xml[:_anonymus].try(:first)
|
||||
end
|
||||
end
|
||||
|
||||
legal = legal_document_xml[:_anonymus].try(:first)
|
||||
xml[:_anonymus] << ident if ident.present?
|
||||
xml[:_anonymus] << legal if legal.present?
|
||||
xml
|
||||
end
|
||||
|
||||
def ident_xml
|
||||
{
|
||||
_anonymus: [
|
||||
ident: { value: ident, attrs: { type: ident_type, cc: ident_country_code } }
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def legal_document_xml
|
||||
return {} if legal_document.blank?
|
||||
|
||||
type = legal_document.original_filename.split('.').last.downcase
|
||||
{
|
||||
_anonymus: [
|
||||
legalDocument: { value: Base64.encode64(legal_document.read), attrs: { type: type } }
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def check(id)
|
||||
xml = epp_xml.check(id: { value: id })
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def country_name
|
||||
Country.new(country_code) || 'No access'
|
||||
end
|
||||
|
||||
def org?
|
||||
ident_type == 'org'
|
||||
end
|
||||
|
||||
def priv?
|
||||
ident_type == 'priv'
|
||||
end
|
||||
|
||||
def persisted?
|
||||
id.present?
|
||||
end
|
||||
|
||||
def handle_errors(data)
|
||||
data.css('result').each do |x|
|
||||
success_codes = %(1000, 1300, 1301)
|
||||
next if success_codes.include?(x['code'])
|
||||
|
||||
message = "#{x.css('msg').text} #{x.css('value').text}"
|
||||
attr = message.split('[').last.strip.sub(']', '') if message.include?('[')
|
||||
attr = :base if attr.nil?
|
||||
attr = 'phone' if attr == 'voice'
|
||||
attr = 'zip' if attr == 'pc'
|
||||
errors.add(attr, message)
|
||||
end
|
||||
errors.blank?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Depp
|
||||
class Dnskey
|
||||
FLAGS = [
|
||||
['0 - not for DNSSEC validation', 0],
|
||||
['256 - ZSK', 256],
|
||||
['257 - KSK', 257]
|
||||
]
|
||||
|
||||
ALGORITHMS = [
|
||||
['3 - DSA/SHA-1', 3],
|
||||
['5 - RSA/SHA-1', 5],
|
||||
['6 - DSA-NSEC3-SHA1', 6],
|
||||
['7 - RSASHA1-NSEC3-SHA1', 7],
|
||||
['8 - RSA/SHA-256', 8],
|
||||
['10 - RSA/SHA-512', 10],
|
||||
['13 - ECDSA Curve P-256 with SHA-256', 13],
|
||||
['14 - ECDSA Curve P-384 with SHA-384', 14],
|
||||
['15 - Ed25519', 15],
|
||||
['16 - Ed448', 16],
|
||||
].freeze
|
||||
|
||||
PROTOCOLS = [3]
|
||||
|
||||
DS_DIGEST_TYPES = [1, 2]
|
||||
end
|
||||
end
|
|
@ -1,351 +0,0 @@
|
|||
module Depp
|
||||
class Domain
|
||||
include ActiveModel::Conversion
|
||||
include RemoveHold
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :name, :current_user, :epp_xml
|
||||
|
||||
STATUSES = %w[
|
||||
clientDeleteProhibited
|
||||
clientHold
|
||||
clientRenewProhibited
|
||||
clientTransferProhibited
|
||||
clientUpdateProhibited
|
||||
].freeze
|
||||
|
||||
PERIODS = [
|
||||
['3 months', '3m'],
|
||||
['6 months', '6m'],
|
||||
['9 months', '9m'],
|
||||
['1 year', '1y'],
|
||||
['2 years', '2y'],
|
||||
['3 years', '3y'],
|
||||
['4 years', '4y'],
|
||||
['5 years', '5y'],
|
||||
['6 years', '6y'],
|
||||
['7 years', '7y'],
|
||||
['8 years', '8y'],
|
||||
['9 years', '9y'],
|
||||
['10 years', '10y'],
|
||||
].freeze
|
||||
|
||||
def initialize(args = {})
|
||||
self.current_user = args[:current_user]
|
||||
self.epp_xml = EppXml::Domain.new(
|
||||
cl_trid_prefix: current_user.tag,
|
||||
schema_prefix: 'domain-ee',
|
||||
schema_version: '1.1'
|
||||
)
|
||||
end
|
||||
|
||||
def info(domain_name)
|
||||
xml = epp_xml.info(name: { value: domain_name })
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def check(domain_name)
|
||||
xml = epp_xml.check(
|
||||
_anonymus: [
|
||||
name: { value: domain_name }
|
||||
]
|
||||
)
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def create(domain_params)
|
||||
dns_hash = {}
|
||||
keys = Domain.create_dnskeys_hash(domain_params)
|
||||
dns_hash[:_anonymus] = keys if keys.any?
|
||||
|
||||
period = domain_params[:period].to_i.to_s
|
||||
period_unit = domain_params[:period][-1].to_s
|
||||
|
||||
xml = if domain_params[:nameservers_attributes]
|
||||
.select { |_key, value| value['hostname'].present? }.any?
|
||||
epp_xml.create({
|
||||
name: { value: domain_params[:name] },
|
||||
period: { value: period, attrs: { unit: period_unit } },
|
||||
ns: Domain.create_nameservers_hash(domain_params),
|
||||
registrant: { value: domain_params[:registrant] },
|
||||
_anonymus: Domain.create_contacts_hash(domain_params)
|
||||
}, dns_hash, Domain.construct_custom_params_hash(domain_params))
|
||||
else
|
||||
epp_xml.create({
|
||||
name: { value: domain_params[:name] },
|
||||
period: { value: period, attrs: { unit: period_unit } },
|
||||
registrant: { value: domain_params[:registrant] },
|
||||
_anonymus: Domain.create_contacts_hash(domain_params)
|
||||
}, dns_hash, Domain.construct_custom_params_hash(domain_params))
|
||||
end
|
||||
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def update(domain_params)
|
||||
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
|
||||
old_domain_params = Depp::Domain.construct_params_from_server_data(data)
|
||||
|
||||
xml = epp_xml.update(
|
||||
Depp::Domain.construct_edit_hash(domain_params, old_domain_params),
|
||||
Depp::Domain.construct_ext_edit_hash(domain_params, old_domain_params),
|
||||
Depp::Domain.construct_custom_params_hash(domain_params)
|
||||
)
|
||||
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def delete(domain_params)
|
||||
xml = epp_xml.delete({
|
||||
name: { value: domain_params[:name] },
|
||||
},
|
||||
Depp::Domain.construct_custom_params_hash(domain_params),
|
||||
(domain_params[:verified].present? && 'yes'))
|
||||
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
def renew(params)
|
||||
period = params[:period].to_i.to_s
|
||||
period_unit = params[:period][-1].to_s
|
||||
|
||||
current_user.request(epp_xml.renew(name: { value: params[:domain_name] },
|
||||
curExpDate: { value: params[:cur_exp_date] },
|
||||
period: { value: period, attrs: { unit: period_unit } }))
|
||||
end
|
||||
|
||||
def transfer(params)
|
||||
op = params[:request] ? 'request' : nil
|
||||
op = params[:query] ? 'query' : op
|
||||
op = params[:approve] ? 'approve' : op
|
||||
op = params[:reject] ? 'reject' : op
|
||||
|
||||
current_user.request(epp_xml.transfer({
|
||||
name: { value: params[:domain_name] },
|
||||
authInfo: { pw: { value: params[:transfer_code] } }
|
||||
}, op, Domain.construct_custom_params_hash(params)))
|
||||
end
|
||||
|
||||
def confirm_transfer(domain_params)
|
||||
data = current_user.request(epp_xml.info(name: { value: domain_params[:name] }))
|
||||
pw = data.css('pw').text
|
||||
|
||||
xml = epp_xml.transfer({
|
||||
name: { value: domain_params[:name] },
|
||||
authInfo: { pw: { value: pw } }
|
||||
}, 'approve')
|
||||
|
||||
current_user.request(xml)
|
||||
end
|
||||
|
||||
class << self
|
||||
def default_period
|
||||
'1y'
|
||||
end
|
||||
|
||||
def default_params
|
||||
ret = {}
|
||||
|
||||
ret[:contacts_attributes] ||= {}
|
||||
ENV['default_admin_contacts_count'].to_i.times do |i|
|
||||
ret[:contacts_attributes][i] = { code: '', type: 'admin' }
|
||||
end
|
||||
|
||||
ret[:nameservers_attributes] ||= {}
|
||||
ENV['default_nameservers_count'].to_i.times do |i|
|
||||
ret[:nameservers_attributes][i] = {}
|
||||
end
|
||||
|
||||
ret[:dnskeys_attributes] ||= { 0 => {} }
|
||||
ret[:statuses_attributes] ||= { 0 => {} }
|
||||
ret.with_indifferent_access
|
||||
end
|
||||
|
||||
def construct_params_from_server_data(data)
|
||||
ret = default_params
|
||||
ret[:name] = data.css('name').text
|
||||
ret[:registrant] = data.css('registrant').text
|
||||
|
||||
data.css('contact').each_with_index do |x, i|
|
||||
ret[:contacts_attributes][i] = { code: x.text, type: x['type'] }
|
||||
end
|
||||
|
||||
data.css('hostAttr').each_with_index do |x, i|
|
||||
ret[:nameservers_attributes][i] = {
|
||||
hostname: x.css('hostName').text,
|
||||
ipv4: Array(x.css('hostAddr[ip="v4"]')).map(&:text).join(','),
|
||||
ipv6: Array(x.css('hostAddr[ip="v6"]')).map(&:text).join(',')
|
||||
}
|
||||
end
|
||||
|
||||
data.css('keyData').each_with_index do |x, i|
|
||||
ret[:dnskeys_attributes][i] = {
|
||||
flags: x.css('flags').text,
|
||||
protocol: x.css('protocol').text,
|
||||
alg: x.css('alg').text,
|
||||
public_key: x.css('pubKey').text,
|
||||
ds_key_tag: x.css('keyTag').first.try(:text),
|
||||
ds_alg: x.css('alg').first.try(:text),
|
||||
ds_digest_type: x.css('digestType').first.try(:text),
|
||||
ds_digest: x.css('digest').first.try(:text)
|
||||
}
|
||||
end
|
||||
|
||||
data.css('status').each_with_index do |x, i|
|
||||
next unless STATUSES.include?(x['s'])
|
||||
|
||||
ret[:statuses_attributes][i] = {
|
||||
code: x['s'],
|
||||
description: x.text
|
||||
}
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def construct_custom_params_hash(domain_params)
|
||||
custom_params = { _anonymus: [] }
|
||||
if domain_params[:legal_document].present?
|
||||
type = domain_params[:legal_document].original_filename.split('.').last.downcase
|
||||
custom_params[:_anonymus] << {
|
||||
legalDocument: { value: Base64.encode64(domain_params[:legal_document].read), attrs: { type: type } }
|
||||
}
|
||||
end
|
||||
|
||||
if domain_params[:reserved_pw].present?
|
||||
custom_params[:_anonymus] << { reserved: { pw: { value: domain_params[:reserved_pw] } } }
|
||||
end
|
||||
|
||||
custom_params
|
||||
end
|
||||
|
||||
def construct_edit_hash(domain_params, old_domain_params)
|
||||
contacts = array_difference(create_contacts_hash(domain_params), create_contacts_hash(old_domain_params))
|
||||
add_anon = contacts
|
||||
|
||||
contacts = array_difference(create_contacts_hash(old_domain_params), create_contacts_hash(domain_params))
|
||||
rem_anon = contacts
|
||||
|
||||
add_arr = []
|
||||
add_ns = create_nameservers_hash(domain_params) - create_nameservers_hash(old_domain_params)
|
||||
add_arr << { ns: add_ns } if add_ns.any?
|
||||
add_arr << { _anonymus: add_anon } if add_anon.any?
|
||||
|
||||
rem_arr = []
|
||||
rem_ns = create_nameservers_hash(old_domain_params) - create_nameservers_hash(domain_params)
|
||||
rem_arr << { ns: rem_ns } if rem_ns.any?
|
||||
rem_arr << { _anonymus: rem_anon } if rem_anon.any?
|
||||
|
||||
if domain_params[:registrant] != old_domain_params[:registrant]
|
||||
chg = [{ registrant: { value: domain_params[:registrant] } }] unless domain_params[:verified].present?
|
||||
if domain_params[:verified]
|
||||
chg = [{ registrant: { value: domain_params[:registrant], attrs: { verified: 'yes' } } }]
|
||||
end
|
||||
end
|
||||
|
||||
add_arr = nil if add_arr.none?
|
||||
rem_arr = nil if rem_arr.none?
|
||||
|
||||
{
|
||||
name: { value: domain_params[:name] },
|
||||
add: add_arr,
|
||||
rem: rem_arr,
|
||||
chg: chg
|
||||
}
|
||||
end
|
||||
|
||||
def construct_ext_edit_hash(domain_params, old_domain_params)
|
||||
rem_keys = create_dnskeys_hash(old_domain_params) - create_dnskeys_hash(domain_params)
|
||||
add_keys = create_dnskeys_hash(domain_params) - create_dnskeys_hash(old_domain_params)
|
||||
hash = {}
|
||||
hash[:rem] = rem_keys if rem_keys.any?
|
||||
hash[:add] = add_keys if add_keys.any?
|
||||
hash
|
||||
end
|
||||
|
||||
def create_nameservers_hash(domain_params)
|
||||
ret = []
|
||||
domain_params[:nameservers_attributes].each do |_k, v|
|
||||
next if v['hostname'].blank?
|
||||
|
||||
host_attr = []
|
||||
host_attr << { hostName: { value: v['hostname'] } }
|
||||
if v['ipv4'].present?
|
||||
v['ipv4'].to_s.split(',').each do |ip|
|
||||
host_attr << { hostAddr: { value: ip, attrs: { ip: 'v4' } } }
|
||||
end
|
||||
end
|
||||
|
||||
if v['ipv6'].present?
|
||||
v['ipv6'].to_s.split(',').each do |ip|
|
||||
host_attr << { hostAddr: { value: ip, attrs: { ip: 'v6' } } }
|
||||
end
|
||||
end
|
||||
|
||||
ret << { hostAttr: host_attr }
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def create_contacts_hash(domain_params)
|
||||
ret = []
|
||||
domain_params[:contacts_attributes].each do |_k, v|
|
||||
next if v['code'].blank?
|
||||
|
||||
ret << {
|
||||
contact: { value: v['code'], attrs: { type: v['type'] } }
|
||||
}
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def create_dnskeys_hash(domain_params)
|
||||
ret = []
|
||||
domain_params[:dnskeys_attributes].each do |_k, v|
|
||||
if v['ds_key_tag'].blank?
|
||||
kd = create_key_data_hash(v)
|
||||
if kd
|
||||
ret << {
|
||||
keyData: kd
|
||||
}
|
||||
end
|
||||
else
|
||||
ret << {
|
||||
dsData: [
|
||||
keyTag: { value: v['ds_key_tag'] },
|
||||
alg: { value: v['ds_alg'] },
|
||||
digestType: { value: v['ds_digest_type'] },
|
||||
digest: { value: v['ds_digest'] },
|
||||
keyData: create_key_data_hash(v)
|
||||
]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
ret
|
||||
end
|
||||
|
||||
def create_key_data_hash(key_data_params)
|
||||
return nil if key_data_params['public_key'].blank?
|
||||
|
||||
{
|
||||
flags: { value: key_data_params['flags'] },
|
||||
protocol: { value: key_data_params['protocol'] },
|
||||
alg: { value: key_data_params['alg'] },
|
||||
pubKey: { value: key_data_params['public_key'] }
|
||||
}
|
||||
end
|
||||
|
||||
def array_difference(x, y)
|
||||
ret = x.dup
|
||||
y.each do |element|
|
||||
index = ret.index(element)
|
||||
ret.delete_at(index) if index
|
||||
end
|
||||
ret
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,66 +0,0 @@
|
|||
module Depp
|
||||
class User
|
||||
include ActiveModel::Validations
|
||||
include ActiveModel::Conversion
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :tag, :password, :pki
|
||||
|
||||
validates :tag, :password, presence: true
|
||||
|
||||
validate :validate_existance_in_server
|
||||
|
||||
def initialize(args = {})
|
||||
args.each { |k, v| send("#{k}=", v) }
|
||||
end
|
||||
|
||||
def server
|
||||
client_cert = File.read(ENV['cert_path'])
|
||||
client_key = File.read(ENV['key_path'])
|
||||
port = ENV['epp_port'] || '700'
|
||||
|
||||
@server_cache ||= Epp::Server.new({
|
||||
server: ENV['epp_hostname'],
|
||||
tag: tag,
|
||||
password: password,
|
||||
port: port,
|
||||
cert: OpenSSL::X509::Certificate.new(client_cert),
|
||||
key: OpenSSL::PKey::RSA.new(client_key)
|
||||
})
|
||||
end
|
||||
|
||||
def request(xml)
|
||||
Nokogiri::XML(server.request(xml)).remove_namespaces!
|
||||
rescue EppErrorResponse => e
|
||||
Nokogiri::XML(e.response_xml.to_s).remove_namespaces!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_existance_in_server
|
||||
return if errors.any?
|
||||
res = server.open_connection
|
||||
unless Nokogiri::XML(res).css('greeting')
|
||||
errors.add(:base, :failed_to_open_connection_to_epp_server)
|
||||
server.close_connection # just in case
|
||||
return
|
||||
end
|
||||
|
||||
ex = EppXml::Session.new(cl_trid_prefix: tag)
|
||||
xml = ex.login(clID: { value: tag }, pw: { value: password })
|
||||
res = server.send_request(xml)
|
||||
|
||||
if Nokogiri::XML(res).css('result').first['code'] != '1000'
|
||||
errors.add(:base, Nokogiri::XML(res).css('result').text)
|
||||
end
|
||||
|
||||
server.close_connection
|
||||
|
||||
rescue OpenSSL::SSL::SSLError => e
|
||||
Rails.logger.error "INVALID CERT: #{e}"
|
||||
Rails.logger.error "INVALID CERT DEBUG INFO: epp_hostname: #{ENV['epp_hostname']}," \
|
||||
"port: #{ENV['epp_port']}, cert_path: #{ENV['cert_path']}, key_path: #{ENV['key_path']}"
|
||||
errors.add(:base, :invalid_cert)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,10 +25,10 @@ class Dnskey < ApplicationRecord
|
|||
}
|
||||
|
||||
# IANA numbers, single authority list
|
||||
ALGORITHMS = Depp::Dnskey::ALGORITHMS.map {|pair| pair[1].to_s}.freeze
|
||||
PROTOCOLS = %w(3)
|
||||
FLAGS = %w(0 256 257) # 256 = ZSK, 257 = KSK
|
||||
DS_DIGEST_TYPE = [1,2]
|
||||
ALGORITHMS = %w[3 5 6 7 8 10 13 14 15 16].freeze
|
||||
PROTOCOLS = %w[3].freeze
|
||||
FLAGS = %w[0 256 257].freeze # 256 = ZSK, 257 = KSK
|
||||
DS_DIGEST_TYPE = [1, 2].freeze
|
||||
RESOLVERS = ENV['dnssec_resolver_ips'].to_s.strip.split(', ').freeze
|
||||
self.ignored_columns = %w[legacy_domain_id]
|
||||
|
||||
|
|
|
@ -13,6 +13,22 @@ class Domain < ApplicationRecord
|
|||
include Domain::Disputable
|
||||
include Domain::BulkUpdatable
|
||||
|
||||
PERIODS = [
|
||||
['3 months', '3m'],
|
||||
['6 months', '6m'],
|
||||
['9 months', '9m'],
|
||||
['1 year', '1y'],
|
||||
['2 years', '2y'],
|
||||
['3 years', '3y'],
|
||||
['4 years', '4y'],
|
||||
['5 years', '5y'],
|
||||
['6 years', '6y'],
|
||||
['7 years', '7y'],
|
||||
['8 years', '8y'],
|
||||
['9 years', '9y'],
|
||||
['10 years', '10y'],
|
||||
].freeze
|
||||
|
||||
attr_accessor :roles,
|
||||
:legal_document_id,
|
||||
:is_admin,
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
class Registrar::DomainListCsvPresenter
|
||||
def initialize(domains:, view:)
|
||||
@domains = domains
|
||||
@view = view
|
||||
end
|
||||
|
||||
def to_s
|
||||
table = CSV::Table.new([header])
|
||||
|
||||
domains.each do |domain|
|
||||
table << domain_to_row(domain: domain)
|
||||
end
|
||||
|
||||
table.to_s
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def header
|
||||
columns = %w[
|
||||
domain_name
|
||||
transfer_code
|
||||
registrant_name
|
||||
registrant_code
|
||||
expire_time
|
||||
]
|
||||
|
||||
columns.map! { |column| view.t("registrar.domains.index.csv.#{column}") }
|
||||
|
||||
CSV::Row.new(columns, [], true)
|
||||
end
|
||||
|
||||
def domain_to_row(domain:)
|
||||
row = []
|
||||
row[0] = domain.name
|
||||
row[1] = domain.transfer_code
|
||||
row[2] = domain.registrant.name
|
||||
row[3] = domain.registrant.code
|
||||
row[4] = domain.expire_date
|
||||
|
||||
CSV::Row.new([], row)
|
||||
end
|
||||
|
||||
attr_reader :domains, :view
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
- content_for :actions do
|
||||
= link_to(t(:add), new_admin_invoice_path, class: 'btn btn-primary')
|
||||
= render 'shared/title', name: t(:invoices)
|
||||
= render 'search_form'
|
||||
= render 'admin/invoices/partials/search_form'
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
|
|
23
app/views/admin/invoices/partials/_buyer.haml
Normal file
23
app/views/admin/invoices/partials/_buyer.haml
Normal file
|
@ -0,0 +1,23 @@
|
|||
%h4= t(:buyer)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:name)
|
||||
%dd= @invoice.buyer_name
|
||||
|
||||
%dt= t(:reg_no)
|
||||
%dd= @invoice.buyer_reg_no
|
||||
|
||||
%dt= t(:address)
|
||||
%dd= @invoice.buyer_address
|
||||
|
||||
%dt= t(:country)
|
||||
%dd= @invoice.buyer_country
|
||||
|
||||
%dt= t(:phone)
|
||||
%dd= @invoice.buyer_phone
|
||||
|
||||
%dt= t(:url)
|
||||
%dd= @invoice.buyer_url
|
||||
|
||||
%dt= t(:email)
|
||||
%dd= @invoice.buyer_email
|
|
@ -36,4 +36,4 @@
|
|||
%dd=@invoice.description
|
||||
|
||||
%dt= Invoice.human_attribute_name :reference_no
|
||||
%dd= @invoice.reference_no
|
||||
%dd= @invoice.reference_no
|
32
app/views/admin/invoices/partials/_items.haml
Normal file
32
app/views/admin/invoices/partials/_items.haml
Normal file
|
@ -0,0 +1,32 @@
|
|||
%h4= t(:items)
|
||||
%hr
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-4'}= t(:description)
|
||||
%th{class: 'col-xs-2'}= t(:unit)
|
||||
%th{class: 'col-xs-2'}= InvoiceItem.human_attribute_name :quantity
|
||||
%th{class: 'col-xs-2'}= t(:price)
|
||||
%th{class: 'col-xs-2'}= t(:total)
|
||||
%tbody
|
||||
- @invoice.each do |invoice_item|
|
||||
%tr
|
||||
%td= invoice_item.description
|
||||
%td= invoice_item.unit
|
||||
%td= invoice_item.quantity
|
||||
%td= currency(invoice_item.price)
|
||||
%td= currency(invoice_item.item_sum_without_vat)
|
||||
%tfoot
|
||||
%tr
|
||||
%th{colspan: 3}
|
||||
%th= Invoice.human_attribute_name :subtotal
|
||||
%td= number_to_currency @invoice.subtotal
|
||||
%tr
|
||||
%th.no-border{colspan: 3}
|
||||
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
|
||||
%td= number_to_currency @invoice.vat_amount
|
||||
%tr
|
||||
%th.no-border{colspan: 3}
|
||||
%th= t(:total)
|
||||
%td= number_to_currency @invoice.total
|
19
app/views/admin/invoices/partials/_payment_orders.haml
Normal file
19
app/views/admin/invoices/partials/_payment_orders.haml
Normal file
|
@ -0,0 +1,19 @@
|
|||
%h4= "Payment Orders"
|
||||
%hr
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-1'}= "#"
|
||||
%th{class: 'col-xs-1'}= "Channel"
|
||||
%th{class: 'col-xs-2'}= "Status"
|
||||
%th{class: 'col-xs-3'}= "Initiated"
|
||||
%th{class: 'col-xs-4'}= "Notes"
|
||||
%tbody
|
||||
- @invoice.payment_orders.each do |payment_order|
|
||||
%tr
|
||||
%td= payment_order.id
|
||||
%td= payment_order.channel
|
||||
%td= payment_order.status
|
||||
%td= payment_order.created_at
|
||||
%td= payment_order.notes
|
|
@ -69,10 +69,10 @@
|
|||
<span class="glyphicon glyphicon-search"></span>
|
||||
|
||||
</button>
|
||||
<%= link_to t('.download_btn'), admin_invoices_path(format: :csv, params: params.permit!),
|
||||
"data-toggle" => "tooltip", "data-placement" => "bottom", "title" => t('.download_btn'),
|
||||
<%= link_to t('admin.invoices.search_form.download_btn'), admin_invoices_path(format: :csv, params: params.permit!),
|
||||
"data-toggle" => "tooltip", "data-placement" => "bottom", "title" => t('admin.invoices.search_form.download_btn'),
|
||||
class: 'btn btn-default' %>
|
||||
<%= link_to t('.reset_btn'), admin_invoices_path, class: 'btn btn-default' %>
|
||||
<%= link_to t('admin.invoices.search_form.reset_btn'), admin_invoices_path, class: 'btn btn-default' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
38
app/views/admin/invoices/partials/_seller.haml
Normal file
38
app/views/admin/invoices/partials/_seller.haml
Normal file
|
@ -0,0 +1,38 @@
|
|||
%h4= t(:seller)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:name)
|
||||
%dd= @invoice.seller_name
|
||||
|
||||
%dt= Registrar.human_attribute_name :reg_no
|
||||
%dd= @invoice.seller_reg_no
|
||||
|
||||
%dt= t(:iban)
|
||||
%dd= @invoice.seller_iban
|
||||
|
||||
%dt= t(:bank)
|
||||
%dd= @invoice.seller_bank
|
||||
|
||||
%dt= t(:swift)
|
||||
%dd= @invoice.seller_swift
|
||||
|
||||
%dt= Registrar.human_attribute_name :vat_no
|
||||
%dd= @invoice.seller_vat_no
|
||||
|
||||
%dt= t(:address)
|
||||
%dd= @invoice.seller_address
|
||||
|
||||
%dt= t(:country)
|
||||
%dd= @invoice.seller_country
|
||||
|
||||
%dt= t(:phone)
|
||||
%dd= @invoice.seller_phone
|
||||
|
||||
%dt= t(:url)
|
||||
%dd= @invoice.seller_url
|
||||
|
||||
%dt= t(:email)
|
||||
%dd= @invoice.seller_email
|
||||
|
||||
%dt= t(:issuer)
|
||||
%dd= @invoice.seller_contact_name
|
|
@ -20,200 +20,14 @@
|
|||
= render 'shared/full_errors', object: @invoice
|
||||
|
||||
.row
|
||||
.col-md-6
|
||||
%h4= t(:details)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:issue_date)
|
||||
%dd= l @invoice.issue_date
|
||||
|
||||
- if @invoice.cancelled?
|
||||
%dt= Invoice.human_attribute_name :cancelled_at
|
||||
%dd= l @invoice.cancelled_at
|
||||
|
||||
%dt= t(:due_date)
|
||||
- if @invoice.cancelled?
|
||||
%dd.text-grey= t(:cancelled)
|
||||
- else
|
||||
%dd= l @invoice.due_date
|
||||
|
||||
%dt= Invoice.human_attribute_name :receipt_date
|
||||
- if @invoice.paid?
|
||||
%dd= l @invoice.receipt_date
|
||||
- elsif @invoice.cancelled?
|
||||
%dd.text-grey= t(:cancelled)
|
||||
- else
|
||||
%dd{class: 'text-danger'}= t(:unpaid)
|
||||
|
||||
%dt= t(:payment_term)
|
||||
%dd Prepayment
|
||||
|
||||
%dt= t(:invoice_number)
|
||||
%dd= @invoice.number
|
||||
|
||||
- if @invoice.description.present?
|
||||
%dt= t(:description)
|
||||
%dd=@invoice.description
|
||||
|
||||
%dt= Invoice.human_attribute_name :reference_no
|
||||
%dd= @invoice.reference_no
|
||||
.col-md-6= render 'admin/invoices/partials/details'
|
||||
.row
|
||||
.col-md-6
|
||||
%h4= t(:seller)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:name)
|
||||
%dd= @invoice.seller_name
|
||||
|
||||
%dt= Registrar.human_attribute_name :reg_no
|
||||
%dd= @invoice.seller_reg_no
|
||||
|
||||
%dt= t(:iban)
|
||||
%dd= @invoice.seller_iban
|
||||
|
||||
%dt= t(:bank)
|
||||
%dd= @invoice.seller_bank
|
||||
|
||||
%dt= t(:swift)
|
||||
%dd= @invoice.seller_swift
|
||||
|
||||
%dt= Registrar.human_attribute_name :vat_no
|
||||
%dd= @invoice.seller_vat_no
|
||||
|
||||
%dt= t(:address)
|
||||
%dd= @invoice.seller_address
|
||||
|
||||
%dt= t(:country)
|
||||
%dd= @invoice.seller_country
|
||||
|
||||
%dt= t(:phone)
|
||||
%dd= @invoice.seller_phone
|
||||
|
||||
%dt= t(:url)
|
||||
%dd= @invoice.seller_url
|
||||
|
||||
%dt= t(:email)
|
||||
%dd= @invoice.seller_email
|
||||
|
||||
%dt= t(:issuer)
|
||||
%dd= @invoice.seller_contact_name
|
||||
.col-md-6
|
||||
%h4= t(:buyer)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:name)
|
||||
%dd= @invoice.buyer_name
|
||||
|
||||
%dt= t(:reg_no)
|
||||
%dd= @invoice.buyer_reg_no
|
||||
|
||||
%dt= t(:address)
|
||||
%dd= @invoice.buyer_address
|
||||
|
||||
%dt= t(:country)
|
||||
%dd= @invoice.buyer_country
|
||||
|
||||
%dt= t(:phone)
|
||||
%dd= @invoice.buyer_phone
|
||||
|
||||
%dt= t(:url)
|
||||
%dd= @invoice.buyer_url
|
||||
|
||||
%dt= t(:email)
|
||||
%dd= @invoice.buyer_email
|
||||
.col-md-6= render 'admin/invoices/partials/seller'
|
||||
.col-md-6= render 'admin/invoices/partials/buyer'
|
||||
.row
|
||||
- if @invoice.monthly_invoice
|
||||
.col-md-12
|
||||
%h4= t(:items)
|
||||
%hr
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-1'}= t(:code)
|
||||
%th{class: 'col-xs-1'}= InvoiceItem.human_attribute_name :quantity
|
||||
%th{class: 'col-xs-1'}= t(:unit)
|
||||
%th{class: 'col-xs-5'}= t(:description)
|
||||
%th{class: 'col-xs-2'}= t(:price)
|
||||
%th{class: 'col-xs-2'}= t(:total)
|
||||
%tbody
|
||||
- @invoice.each do |invoice_item|
|
||||
%tr
|
||||
%td= invoice_item.product_id
|
||||
%td= invoice_item.quantity
|
||||
%td= invoice_item.unit
|
||||
%td= invoice_item.description
|
||||
- if invoice_item.price && invoice_item.quantity
|
||||
%td= currency(invoice_item.price)
|
||||
%td= "#{currency((invoice_item.price * invoice_item.quantity).round(3))} #{@invoice.currency}"
|
||||
- else
|
||||
%td= ''
|
||||
%td= ''
|
||||
%tfoot
|
||||
%tr
|
||||
%th{colspan: 4}
|
||||
%th= Invoice.human_attribute_name :subtotal
|
||||
%td= number_to_currency(0)
|
||||
%tr
|
||||
%th.no-border{colspan: 4}
|
||||
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
|
||||
%td= number_to_currency(0)
|
||||
%tr
|
||||
%th.no-border{colspan: 4}
|
||||
%th= t(:total)
|
||||
%td= number_to_currency(0)
|
||||
- if @invoice.monthly_invoice
|
||||
.col-md-12= render 'admin/invoices/partials/monthly_invoice_items'
|
||||
- else
|
||||
.col-md-12
|
||||
%h4= t(:items)
|
||||
%hr
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-4'}= t(:description)
|
||||
%th{class: 'col-xs-2'}= t(:unit)
|
||||
%th{class: 'col-xs-2'}= InvoiceItem.human_attribute_name :quantity
|
||||
%th{class: 'col-xs-2'}= t(:price)
|
||||
%th{class: 'col-xs-2'}= t(:total)
|
||||
%tbody
|
||||
- @invoice.each do |invoice_item|
|
||||
%tr
|
||||
%td= invoice_item.description
|
||||
%td= invoice_item.unit
|
||||
%td= invoice_item.quantity
|
||||
%td= currency(invoice_item.price)
|
||||
%td= currency(invoice_item.item_sum_without_vat)
|
||||
%tfoot
|
||||
%tr
|
||||
%th{colspan: 3}
|
||||
%th= Invoice.human_attribute_name :subtotal
|
||||
%td= number_to_currency @invoice.subtotal
|
||||
%tr
|
||||
%th.no-border{colspan: 3}
|
||||
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
|
||||
%td= number_to_currency @invoice.vat_amount
|
||||
%tr
|
||||
%th.no-border{colspan: 3}
|
||||
%th= t(:total)
|
||||
%td= number_to_currency @invoice.total
|
||||
.col-md-12= render 'admin/invoices/partials/items'
|
||||
.row
|
||||
.col-md-12
|
||||
%h4= "Payment Orders"
|
||||
%hr
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-1'}= "#"
|
||||
%th{class: 'col-xs-1'}= "Channel"
|
||||
%th{class: 'col-xs-2'}= "Status"
|
||||
%th{class: 'col-xs-3'}= "Initiated"
|
||||
%th{class: 'col-xs-4'}= "Notes"
|
||||
%tbody
|
||||
- @invoice.payment_orders.each do |payment_order|
|
||||
%tr
|
||||
%td= payment_order.id
|
||||
%td= payment_order.channel
|
||||
%td= payment_order.status
|
||||
%td= payment_order.created_at
|
||||
%td= payment_order.notes
|
||||
.col-md-12= render 'admin/invoices/partials/payment_orders'
|
|
@ -1,64 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="<%= I18n.locale.to_s %>">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport"/>
|
||||
<% if content_for? :head_title %>
|
||||
<%= yield :head_title %>
|
||||
<% else %>
|
||||
<title>
|
||||
<%= t(:registrar_head_title) %>
|
||||
</title>
|
||||
<% end %>
|
||||
<%= csrf_meta_tags %>
|
||||
<%= stylesheet_link_tag 'registrar-manifest', media: 'all' %>
|
||||
<%= favicon_link_tag 'favicon.ico' %>
|
||||
</head>
|
||||
<body class="<%= body_css_class %>">
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button aria-expanded="false" class="navbar-toggle collapsed" data-target="#navbar" data-toggle="collapse" type="button">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<%= link_to can?(:show, :poll) ? registrar_root_path : registrar_account_path,
|
||||
class: 'navbar-brand' do %>
|
||||
<%= t(:registrar_head_title) %>
|
||||
<% if unstable_env.present? %>
|
||||
<div class="text-center">
|
||||
<small style="color: #0074B3;">
|
||||
<%= unstable_env %>
|
||||
</small>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render 'navbar' %>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<%= render 'flash_messages' %>
|
||||
<% if depp_controller? %>
|
||||
<%= render 'registrar/shared/epp_results' %>
|
||||
<% end %>
|
||||
<%= yield %>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<%= image_tag 'eis-logo-et.png' %>
|
||||
</div>
|
||||
<div class="col-md-6 text-right">
|
||||
Version
|
||||
<%= current_commit_link %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<%= javascript_include_tag 'registrar-manifest', async: true %>
|
||||
</body>
|
||||
</html>
|
|
@ -1,23 +0,0 @@
|
|||
- content_for :actions do
|
||||
= link_to(t('.download_btn'), download_registrar_invoice_path(@invoice), class: 'btn btn-default')
|
||||
= link_to(t('.deliver_btn'), new_registrar_invoice_delivery_path(@invoice), class: 'btn btn-default')
|
||||
- if @invoice.cancellable?
|
||||
= link_to(t(:cancel), cancel_registrar_invoice_path(@invoice), method: :patch, class: 'btn btn-warning')
|
||||
= link_to(t(:back), registrar_invoices_path, class: 'btn btn-default')
|
||||
= render 'shared/title', name: @invoice.to_s
|
||||
= render 'shared/full_errors', object: @invoice
|
||||
|
||||
.row
|
||||
.col-md-6= render 'registrar/invoices/partials/details'
|
||||
.row
|
||||
.col-md-6= render 'registrar/invoices/partials/seller'
|
||||
.col-md-6= render 'registrar/invoices/partials/buyer'
|
||||
.row
|
||||
- if @invoice.monthly_invoice
|
||||
.col-md-12= render 'registrar/invoices/partials/monthly_invoice_items'
|
||||
- else
|
||||
.col-md-12= render 'registrar/invoices/partials/items'
|
||||
|
||||
- if @invoice.payable?
|
||||
.row.semifooter
|
||||
.col-md-6-offset-6.text-right= render 'registrar/invoices/partials/banklinks', locals: { payment_channels: PaymentOrder::CUSTOMER_PAYMENT_METHODS }
|
|
@ -61,16 +61,6 @@ contact_org_enabled: 'false'
|
|||
# System default for legal document types is: pdf,asice,sce,asics,scs,adoc,edoc,bdoc,ddoc,zip,rar,gz,tar,7z,odt,doc,docx
|
||||
# legal_document_types: "pdf,asice,sce,asics,scs,adoc,edoc,bdoc,ddoc,zip,rar,gz,tar,7z,odt,doc,docx"
|
||||
|
||||
#
|
||||
# REGISTRAR configuration (DEPP)
|
||||
#
|
||||
show_ds_data_fields: 'false'
|
||||
default_nameservers_count: '2'
|
||||
default_admin_contacts_count: '1'
|
||||
epp_port: '700'
|
||||
cert_path: '/home/registry/registry/shared/ca/certs/webclient.cert.pem'
|
||||
key_path: '/home/registry/registry/shared/ca/private/webclient.key.pem'
|
||||
epp_hostname: 'registry.gitlab.eu'
|
||||
repp_url: 'http://epp:3000/repp/v1/'
|
||||
|
||||
# Estonian Company Register
|
||||
|
|
|
@ -380,29 +380,6 @@ en:
|
|||
client_side_status_editing_error: 'Parameter value policy error. Client-side object status management not supported'
|
||||
parameter_value_syntax_error: 'Parameter value syntax error:'
|
||||
|
||||
# DEPP
|
||||
activemodel:
|
||||
errors:
|
||||
models:
|
||||
'depp/contact':
|
||||
attributes:
|
||||
phone:
|
||||
invalid: "Phone number must be in +XXX.YYYYYYY format"
|
||||
too_long: "Phone number is too long"
|
||||
'depp/user':
|
||||
attributes:
|
||||
base:
|
||||
failed_to_open_connection_to_epp_server: 'Failed to open connection to EPP server!'
|
||||
authorization_error: 'Authorization error'
|
||||
invalid_cert: 'Invalid certificate'
|
||||
not_active: 'User is not active'
|
||||
webserver_missing_user_name_directive: 'Webserver configuration error: Apache or nginx is missing user name directive.'
|
||||
webserver_user_name_directive_should_be_required: 'Webserver configuration error: Apache or nginx should require name directive.'
|
||||
tag:
|
||||
blank: "Username can't be blank"
|
||||
password:
|
||||
blank: "Password can't be blank"
|
||||
|
||||
username: 'Username'
|
||||
register: 'Register'
|
||||
domain_info: 'Domain info'
|
||||
|
|
|
@ -24,13 +24,11 @@ class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
|||
{ flags: '256',
|
||||
alg: '14',
|
||||
protocol: '3',
|
||||
public_key: 'dGVzdA=='
|
||||
}
|
||||
]
|
||||
public_key: 'dGVzdA==' },
|
||||
],
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
get "/repp/v1/domains/#{@domain.name}/dnssec", headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
@ -45,9 +43,8 @@ class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
|||
{ flags: '256',
|
||||
alg: '14',
|
||||
protocol: '3',
|
||||
public_key: 'dGVzdA=='
|
||||
}
|
||||
]
|
||||
public_key: 'dGVzdA==' },
|
||||
],
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||
|
@ -67,7 +64,7 @@ class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
|||
end
|
||||
|
||||
def test_creates_dnssec_key_with_every_algo
|
||||
algos = Depp::Dnskey::ALGORITHMS.map {|pair| pair[1].to_s}
|
||||
algos = Dnskey::ALGORITHMS
|
||||
algos_to_check = %w[15 16]
|
||||
|
||||
assert (algos & algos_to_check) == algos_to_check
|
||||
|
@ -79,9 +76,8 @@ class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
|||
{ flags: '256',
|
||||
alg: alg,
|
||||
protocol: '3',
|
||||
public_key: 'dGVzdA=='
|
||||
}
|
||||
]
|
||||
public_key: 'dGVzdA==' },
|
||||
],
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||
|
@ -105,13 +101,11 @@ class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
|||
{ flags: '256',
|
||||
alg: '14',
|
||||
protocol: '3',
|
||||
public_key: 'dGVzdA=='
|
||||
}
|
||||
]
|
||||
public_key: 'dGVzdA==' },
|
||||
],
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert @domain.dnskeys.any?
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
require 'test_helper'
|
||||
require 'helpers/phone_format_helper_test'
|
||||
|
||||
class DeppContactTest < ActiveSupport::TestCase
|
||||
include PhoneFormatHelperTest
|
||||
|
||||
setup do
|
||||
@depp_contact = Depp::Contact.new
|
||||
end
|
||||
|
||||
def test_validates_phone_format
|
||||
assert_phone_format(@depp_contact)
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
require 'application_system_test_case'
|
||||
|
||||
class BalanceTopUpTest < ApplicationSystemTestCase
|
||||
setup do
|
||||
sign_in users(:api_bestnames)
|
||||
@original_registry_vat_rate = Setting.registry_vat_prc
|
||||
|
||||
eis_response = OpenStruct.new(body: "{\"payment_link\":\"http://link.test\"}")
|
||||
Spy.on_instance_method(EisBilling::AddDeposits, :send_invoice).and_return(eis_response)
|
||||
Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true)
|
||||
end
|
||||
|
||||
teardown do
|
||||
Setting.registry_vat_prc = @original_registry_vat_rate
|
||||
end
|
||||
|
||||
def test_creates_new_invoice
|
||||
invoice_n = Invoice.order(number: :desc).last.number
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator").
|
||||
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {})
|
||||
|
||||
stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response")
|
||||
.to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {})
|
||||
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice")
|
||||
.to_return(status: 200, body: "", headers: {})
|
||||
|
||||
Setting.registry_vat_prc = 0.1
|
||||
|
||||
visit registrar_invoices_url
|
||||
click_link_or_button 'Add deposit'
|
||||
fill_in 'Amount', with: '25.5'
|
||||
|
||||
assert_difference 'Invoice.count' do
|
||||
click_link_or_button 'Add'
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
|
||||
assert_equal BigDecimal(10), invoice.vat_rate
|
||||
assert_equal BigDecimal('28.05'), invoice.total
|
||||
assert_text 'Please pay the following invoice'
|
||||
end
|
||||
end
|
|
@ -1,96 +0,0 @@
|
|||
require 'application_system_test_case'
|
||||
|
||||
class NewInvoiceTest < ApplicationSystemTestCase
|
||||
def setup
|
||||
super
|
||||
|
||||
@user = users(:api_bestnames)
|
||||
sign_in @user
|
||||
|
||||
eis_response = OpenStruct.new(body: "{\"payment_link\":\"http://link.test\"}")
|
||||
Spy.on_instance_method(EisBilling::AddDeposits, :send_invoice).and_return(eis_response)
|
||||
end
|
||||
|
||||
def test_show_balance
|
||||
visit registrar_invoices_path
|
||||
assert_text "Your current account balance is 100,00 EUR"
|
||||
end
|
||||
|
||||
def test_create_new_invoice_with_positive_amount
|
||||
invoice_n = Invoice.order(number: :desc).last.number
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator").
|
||||
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {})
|
||||
|
||||
stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response").
|
||||
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {})
|
||||
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice").
|
||||
to_return(status: 200, body: "", headers: {})
|
||||
|
||||
visit registrar_invoices_path
|
||||
click_link_or_button 'Add deposit'
|
||||
fill_in 'Amount', with: '200.00'
|
||||
fill_in 'Description', with: 'My first invoice'
|
||||
|
||||
assert_difference 'Invoice.count', 1 do
|
||||
click_link_or_button 'Add'
|
||||
end
|
||||
|
||||
assert_text 'Please pay the following invoice'
|
||||
assert_text "Invoice no. #{invoice_n + 3}"
|
||||
assert_text 'Subtotal 200,00 €'
|
||||
assert_text 'Pay invoice'
|
||||
end
|
||||
|
||||
def test_create_new_invoice_with_comma_in_number
|
||||
invoice_n = Invoice.order(number: :desc).last.number
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator").
|
||||
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {})
|
||||
|
||||
stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response").
|
||||
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {})
|
||||
|
||||
stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice").
|
||||
to_return(status: 200, body: "", headers: {})
|
||||
|
||||
visit registrar_invoices_path
|
||||
click_link_or_button 'Add deposit'
|
||||
fill_in 'Amount', with: '200,00'
|
||||
fill_in 'Description', with: 'My first invoice'
|
||||
|
||||
assert_difference 'Invoice.count', 1 do
|
||||
click_link_or_button 'Add'
|
||||
end
|
||||
|
||||
assert_text 'Please pay the following invoice'
|
||||
assert_text "Invoice no. #{invoice_n + 3}"
|
||||
assert_text 'Subtotal 200,00 €'
|
||||
assert_text 'Pay invoice'
|
||||
end
|
||||
|
||||
def test_create_new_invoice_fails_when_amount_is_0
|
||||
visit registrar_invoices_path
|
||||
click_link_or_button 'Add deposit'
|
||||
fill_in 'Amount', with: '0.00'
|
||||
fill_in 'Description', with: 'My first invoice'
|
||||
|
||||
assert_no_difference 'Invoice.count' do
|
||||
click_link_or_button 'Add'
|
||||
end
|
||||
|
||||
assert_text 'Amount is too small. Minimum deposit is 0.01 EUR'
|
||||
end
|
||||
|
||||
def test_create_new_invoice_fails_when_amount_is_negative
|
||||
visit registrar_invoices_path
|
||||
click_link_or_button 'Add deposit'
|
||||
fill_in 'Amount', with: '-120.00'
|
||||
fill_in 'Description', with: 'My first invoice'
|
||||
|
||||
assert_no_difference 'Invoice.count' do
|
||||
click_link_or_button 'Add'
|
||||
end
|
||||
|
||||
assert_text 'Amount is too small. Minimum deposit is 0.01 EUR'
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue