Updated REPP API for new registrar portal

This commit is contained in:
Sergei Tsõganov 2022-06-06 13:43:30 +03:00
parent e17b21436d
commit a5ffce290d
61 changed files with 1269 additions and 408 deletions

View file

@ -34,9 +34,11 @@ class Ability
if @user.registrar.api_ip_white?(@ip)
can :manage, Depp::Contact
can :manage, :xml_console
can :manage, Depp::Domain
can :manage, Depp::Domain
end
can :manage, Account
# Poll
can :manage, :poll
@ -65,12 +67,13 @@ class Ability
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(:transfer, Epp::Contact)
can(:transfer, Epp::Contact)
can(:view_password, Epp::Contact) { |c, pw| c.registrar_id == @user.registrar_id || c.auth_info == pw }
end
def billing # Registrar/api_user dynamic role
can(:manage, Invoice) { |i| i.buyer_id == @user.registrar_id }
can :manage, Account
can :manage, :deposit
can :read, AccountActivity
can :manage, :balance_auto_reload

View file

@ -28,14 +28,20 @@ class Action < ApplicationRecord
end
def to_non_available_contact_codes
return [] unless bulk_action?
return [serialized_contact(contact)] unless bulk_action?
subactions.map do |a|
{
code: a.contact.code,
avail: 0,
reason: 'in use',
}
serialized_contact(a.contact)
end
end
private
def serialized_contact(contact)
{
code: contact.code,
avail: 0,
reason: 'in use',
}
end
end

View file

@ -6,7 +6,7 @@ class AdminDomainContact < DomainContact
skipped_domains = []
admin_contacts = where(contact: current_contact)
admin_contacts.each do |admin_contact|
admin_contacts.includes(:domain).each do |admin_contact|
if admin_contact.domain.bulk_update_prohibited?
skipped_domains << admin_contact.domain.name
next

View file

@ -30,11 +30,11 @@ class ApiUser < User
alias_attribute :login, :username
SUPER = 'super'
EPP = 'epp'
BILLING = 'billing'
SUPER = 'super'.freeze
EPP = 'epp'.freeze
BILLING = 'billing'.freeze
ROLES = %w(super epp billing) # should not match to admin roles
ROLES = %w[super epp billing].freeze # should not match to admin roles
def ability
@ability ||= Ability.new(self)
@ -72,8 +72,8 @@ class ApiUser < User
def linked_users
self.class.where(identity_code: identity_code)
.where("identity_code IS NOT NULL AND identity_code != ''")
.where.not(id: id)
.where("identity_code IS NOT NULL AND identity_code != ''")
.where.not(id: id)
end
def linked_with?(another_api_user)

View file

@ -1,6 +1,7 @@
module BalanceAutoReloadTypes
class Threshold
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :amount, :threshold
@ -11,8 +12,9 @@ module BalanceAutoReloadTypes
Setting.minimum_deposit
end
def as_json(options)
def as_json(options = nil)
{ name: name }.merge(super)
.except('errors', 'validation_context')
end
private

View file

@ -1 +0,0 @@
class BulkAction < Action; end

View file

@ -5,12 +5,22 @@ module Invoice::Cancellable
scope :non_cancelled, -> { where(cancelled_at: nil) }
end
def can_be_cancelled?
unless cancellable?
errors.add(:base, :invoice_status_prohibits_operation)
return false
end
true
end
def cancellable?
unpaid? && not_cancelled?
end
def cancel
raise 'Invoice cannot be cancelled' unless cancellable?
update!(cancelled_at: Time.zone.now)
end

View file

@ -15,6 +15,8 @@ module Invoice::Payable
end
def receipt_date
return unless paid?
account_activity.created_at.to_date
end

View file

@ -80,41 +80,41 @@ class Contact < ApplicationRecord
self.ignored_columns = %w[legacy_id legacy_history_id]
ORG = 'org'
PRIV = 'priv'
ORG = 'org'.freeze
PRIV = 'priv'.freeze
# For foreign private persons who has no national identification number
BIRTHDAY = 'birthday'.freeze
# From old registry software ("Fred"). No new contact can be created with this status
PASSPORT = 'passport'
PASSPORT = 'passport'.freeze
#
# STATUSES
#
# Requests to delete the object MUST be rejected.
CLIENT_DELETE_PROHIBITED = 'clientDeleteProhibited'
SERVER_DELETE_PROHIBITED = 'serverDeleteProhibited'
CLIENT_DELETE_PROHIBITED = 'clientDeleteProhibited'.freeze
SERVER_DELETE_PROHIBITED = 'serverDeleteProhibited'.freeze
# Requests to transfer the object MUST be rejected.
CLIENT_TRANSFER_PROHIBITED = 'clientTransferProhibited'
SERVER_TRANSFER_PROHIBITED = 'serverTransferProhibited'
CLIENT_TRANSFER_PROHIBITED = 'clientTransferProhibited'.freeze
SERVER_TRANSFER_PROHIBITED = 'serverTransferProhibited'.freeze
# The contact object has at least one active association with
# another object, such as a domain object. Servers SHOULD provide
# services to determine existing object associations.
# "linked" status MAY be combined with any status.
LINKED = 'linked'
LINKED = 'linked'.freeze
# This is the normal status value for an object that has no pending
# operations or prohibitions. This value is set and removed by the
# server as other status values are added or removed.
# "ok" status MAY only be combined with "linked" status.
OK = 'ok'
OK = 'ok'.freeze
# Requests to update the object (other than to remove this status) MUST be rejected.
CLIENT_UPDATE_PROHIBITED = 'clientUpdateProhibited'
SERVER_UPDATE_PROHIBITED = 'serverUpdateProhibited'
CLIENT_UPDATE_PROHIBITED = 'clientUpdateProhibited'.freeze
SERVER_UPDATE_PROHIBITED = 'serverUpdateProhibited'.freeze
# A transform command has been processed for the object, but the
# action has not been completed by the server. Server operators can
@ -129,16 +129,16 @@ class Contact < ApplicationRecord
# the status of the object has changed.
# The pendingCreate, pendingDelete, pendingTransfer, and pendingUpdate
# status values MUST NOT be combined with each other.
PENDING_CREATE = 'pendingCreate'
PENDING_CREATE = 'pendingCreate'.freeze
# "pendingTransfer" status MUST NOT be combined with either
# "clientTransferProhibited" or "serverTransferProhibited" status.
PENDING_TRANSFER = 'pendingTransfer'
PENDING_TRANSFER = 'pendingTransfer'.freeze
# "pendingUpdate" status MUST NOT be combined with either
# "clientUpdateProhibited" or "serverUpdateProhibited" status.
PENDING_UPDATE = 'pendingUpdate'
PENDING_UPDATE = 'pendingUpdate'.freeze
# "pendingDelete" MUST NOT be combined with either
# "clientDeleteProhibited" or "serverDeleteProhibited" status.
PENDING_DELETE = 'pendingDelete'
PENDING_DELETE = 'pendingDelete'.freeze
STATUSES = [
CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED,
@ -146,18 +146,18 @@ class Contact < ApplicationRecord
SERVER_TRANSFER_PROHIBITED, CLIENT_UPDATE_PROHIBITED, SERVER_UPDATE_PROHIBITED,
OK, PENDING_CREATE, PENDING_DELETE, PENDING_TRANSFER,
PENDING_UPDATE, LINKED
]
].freeze
CLIENT_STATUSES = [
CLIENT_DELETE_PROHIBITED, CLIENT_TRANSFER_PROHIBITED,
CLIENT_UPDATE_PROHIBITED
]
].freeze
SERVER_STATUSES = [
SERVER_UPDATE_PROHIBITED,
SERVER_DELETE_PROHIBITED,
SERVER_TRANSFER_PROHIBITED
]
SERVER_TRANSFER_PROHIBITED,
].freeze
#
# END OF STATUSES
#
@ -355,7 +355,7 @@ class Contact < ApplicationRecord
@desc[dom.name][:roles] << :registrant
end
domain_contacts.each do |dc|
domain_contacts.includes(:domain).each do |dc|
@desc[dc.domain.name] ||= { id: dc.domain.uuid, roles: [] }
@desc[dc.domain.name][:roles] << dc.name.downcase.to_sym
@desc[dc.domain.name] = @desc[dc.domain.name].compact
@ -383,6 +383,10 @@ class Contact < ApplicationRecord
"#{code} #{name}"
end
def name_disclosed_by_registrar(reg_id)
registrar_id == reg_id ? name : 'N/A'
end
def strip_email
self.email = email.to_s.strip
end
@ -405,7 +409,7 @@ class Contact < ApplicationRecord
# using small rails hack to generate outer join
domains = if sorts.first == 'registrar_name'.freeze
domains.includes(:registrar).where.not(registrars: { id: nil })
domains.where.not(registrars: { id: nil })
.order("registrars.name #{order} NULLS LAST")
else
domains.order("#{sort} #{order} NULLS LAST")
@ -422,7 +426,6 @@ class Contact < ApplicationRecord
end
domains.each { |d| d.roles = domain_c[d.id].uniq }
domains
end
@ -438,18 +441,28 @@ class Contact < ApplicationRecord
end
end
def qualified_domain_ids(domain_filter)
registrant_ids = registrant_domains.pluck(:id)
return registrant_ids if domain_filter == 'Registrant'
def qualified_domain_ids(filters)
rant_domains = registrant_domains.map { |d| { id: d.id, type: ['Registrant'] } }
contact_domains = domain_contacts.map { |dc| { id: dc.domain_id, type: [dc.type] } }
grouped_domains = group_by_id_and_type(rant_domains + contact_domains)
return grouped_domains.keys if filters.nil? || filters == ''
if %w[AdminDomainContact TechDomainContact].include? domain_filter
DomainContact.select('domain_id').where(contact_id: id, type: domain_filter)
else
(DomainContact.select('domain_id').where(contact_id: id).pluck(:domain_id) +
registrant_ids).uniq
end
# use domain_filters.sort == v.sort if should be exact match
grouped_domains.reject { |_, v| ([].push(filters).flatten & v).empty? }.keys
end
# def qualified_domain_ids(domain_filter)
# registrant_ids = registrant_domains.pluck(:id)
# return registrant_ids if domain_filter == 'Registrant'
# if %w[AdminDomainContact TechDomainContact].include? domain_filter
# DomainContact.where(contact_id: id, type: domain_filter).pluck(:domain_id)
# else
# (DomainContact.where(contact_id: id).pluck(:domain_id) +
# registrant_ids).uniq
# end
# end
def update_prohibited?
(statuses & [
CLIENT_UPDATE_PROHIBITED,
@ -459,7 +472,7 @@ class Contact < ApplicationRecord
PENDING_CREATE,
PENDING_TRANSFER,
PENDING_UPDATE,
PENDING_DELETE
PENDING_DELETE,
]).present?
end
@ -590,4 +603,14 @@ class Contact < ApplicationRecord
def self.csv_header
['Name', 'ID', 'Ident', 'E-mail', 'Created at', 'Registrar', 'Phone']
end
private
def group_by_id_and_type(domains_hash_array)
domains_hash_array.group_by { |d| d[:id] }
.transform_values do |v|
v.each.with_object(:type)
.map(&:[]).flatten
end
end
end

View file

@ -0,0 +1 @@
class ContactUpdateAction < Action; end

View file

@ -33,6 +33,7 @@ class Deposit
def issue_prepayment_invoice
return unless valid?
registrar.issue_prepayment_invoice(amount, description)
end
end

View file

@ -31,8 +31,8 @@ module Depp
def request(xml)
Nokogiri::XML(server.request(xml)).remove_namespaces!
rescue EppErrorResponse => e
Nokogiri::XML(e.response_xml.to_s).remove_namespaces!
rescue EppErrorResponse => e
Nokogiri::XML(e.response_xml.to_s).remove_namespaces!
end
private

View file

@ -4,10 +4,10 @@ class DomainTransfer < ApplicationRecord
belongs_to :old_registrar, class_name: 'Registrar'
belongs_to :new_registrar, class_name: 'Registrar'
PENDING = 'pending'
CLIENT_APPROVED = 'clientApproved'
CLIENT_REJECTED = 'clientRejected'
SERVER_APPROVED = 'serverApproved'
PENDING = 'pending'.freeze
CLIENT_APPROVED = 'clientApproved'.freeze
CLIENT_REJECTED = 'clientRejected'.freeze
SERVER_APPROVED = 'serverApproved'.freeze
before_create :set_wait_until

View file

@ -180,6 +180,13 @@ class Invoice < ApplicationRecord
private
ransacker :number_str do
Arel.sql(
"regexp_replace(
to_char(\"#{table_name}\".\"number\", '999999999999'), ' ', '', 'g')"
)
end
def receipt_date_status
if paid?
receipt_date

View file

@ -1,5 +1,6 @@
class Notification < ApplicationRecord
include Versions # version/notification_version.rb
include EppErrors
belongs_to :registrar
belongs_to :action, optional: true

View file

@ -97,7 +97,7 @@ class Registrar < ApplicationRecord
description: 'prepayment',
unit: 'piece',
quantity: 1,
price: amount
price: amount,
}
]
)
@ -233,13 +233,9 @@ class Registrar < ApplicationRecord
def notify(action)
text = I18n.t("notifications.texts.#{action.notification_key}", contact: action.contact&.code,
count: action.subactions&.count)
if action.bulk_action?
notifications.create!(text: text, action_id: action.id,
attached_obj_type: 'BulkAction',
attached_obj_id: action.id)
else
notifications.create!(text: text)
end
notifications.create!(text: text, action_id: action.id,
attached_obj_type: 'ContactUpdateAction',
attached_obj_id: action.id)
end
def e_invoice_iban

View file

@ -5,7 +5,7 @@ class TechDomainContact < DomainContact
skipped_domains = []
tech_contacts = where(contact: current_contact)
tech_contacts.each do |tech_contact|
tech_contacts.includes(:domain).each do |tech_contact|
if irreplaceable?(tech_contact)
skipped_domains << tech_contact.domain.name
next

View file

@ -16,6 +16,6 @@ class User < ApplicationRecord
identity_code = uid.slice(2..-1)
# country_code = uid.slice(0..1)
find_by(identity_code: identity_code)
find_by(identity_code: identity_code, active: true)
end
end