Merge remote-tracking branch 'origin/master' into repp-domains

This commit is contained in:
Karl Erik Õunapuu 2020-12-29 12:47:50 +02:00
commit 221e4ba578
No known key found for this signature in database
GPG key ID: C9DD647298A34764
140 changed files with 2575 additions and 731 deletions

View file

@ -20,6 +20,9 @@ plugins:
channel: eslint-5
fixme:
enabled: true
checks:
TODO:
enabled: false
rubocop:
enabled: true
channel: rubocop-0-74

117
.github/workflows/ruby.yml vendored Normal file
View file

@ -0,0 +1,117 @@
name: Github Testing
on: [push]
jobs:
test:
services:
postgres:
image: postgres:12
ports: ["5432:5432"]
env:
POSTGRES_PASSWORD: password
POSTGRES_USERNAME: postgres
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-18.04]
ruby: [2.6, 2.7 ]
runs-on: ${{ matrix.os }}
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: config bundler
run: |
bundle config set without 'development staging production'
bundle config set deployment '[secure]'
bundle env
head -n1 $(which bundle)
- name: Set ENV for codeclimate (pull_request)
run: |
git fetch --no-tags --prune --depth=1 origin +refs/heads/$GITHUB_HEAD_REF:refs/remotes/origin/$GITHUB_HEAD_REF
echo "GIT_BRANCH=$GITHUB_HEAD_REF" >> $GITHUB_ENV
echo "GIT_COMMIT_SHA=$(git rev-parse origin/$GITHUB_HEAD_REF)" >> $GITHUB_ENV
if: github.event_name == 'pull_request'
- name: Set ENV for codeclimate (push)
run: |
echo "GIT_BRANCH=$GITHUB_REF" >> $GITHUB_ENV
echo "GIT_COMMIT_SHA=$GITHUB_SHA" >> $GITHUB_ENV
if: github.event_name == 'push'
- name: Prepare CodeClimate
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
run: |
curl -LSs 'https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64' >./cc-test-reporter;
chmod +x ./cc-test-reporter
./cc-test-reporter before-build
- name: Run Tests
env:
PG_DATABASE: postgres
PG_HOST: localhost
PG_USER: postgres
PG_PASSWORD: password
PG_PORT: ${{ job.services.postgres.ports[5432] }}
RAILS_ENV: test
COVERAGE: true
DISABLE_SPRING: 1
run: |
cp config/application.yml.sample config/application.yml
cp config/database_travis.yml config/database.yml
echo "openssl_config_path: 'test/fixtures/files/test_ca/openssl.cnf'" >> config/application.yml
echo "crl_dir: 'test/fixtures/files/test_ca/crl'" >> config/application.yml
echo "crl_path: 'test/fixtures/files/test_ca/crl/crl.pem'" >> config/application.yml
echo "ca_cert_path: 'test/fixtures/files/test_ca/certs/ca.crt.pem'" >> config/application.yml
echo "ca_key_path: 'test/fixtures/files/test_ca/private/ca.key.pem'" >> config/application.yml
echo "ca_key_password: 'password'" >> config/application.yml
bundle exec rake db:setup:all
bundle exec rails test test/*
- name: Save coverage
run: ./cc-test-reporter format-coverage --output coverage/codeclimate.${{ matrix.ruby }}.json
- uses: actions/upload-artifact@v1
with:
name: coverage-${{ matrix.ruby }}
path: coverage/codeclimate.${{ matrix.ruby }}.json
upload_coverage:
runs-on: ubuntu-18.04
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
CC_TEST_REPORTER_URL: https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64
needs: test
steps:
- name: Download test coverage reporter
run: curl -L $CC_TEST_REPORTER_URL > cc-test-reporter
- name: Give test coverage reporter executable permissions
run: chmod +x cc-test-reporter
- uses: actions/download-artifact@v1
with:
name: coverage-2.6
path: coverage
- uses: actions/download-artifact@v1
with:
name: coverage-2.7
path: coverage
- name: Aggregate & upload results to Code Climate
run: |
./cc-test-reporter sum-coverage coverage/codeclimate.*.json
./cc-test-reporter upload-coverage

View file

@ -1,35 +0,0 @@
language: ruby
cache: bundler
env:
- DB=postgresql
before_install:
- "wget -N http://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip -P ~/"
- "unzip ~/chromedriver_linux64.zip -d ~/"
- "rm ~/chromedriver_linux64.zip"
- "sudo mv -f ~/chromedriver /usr/local/share/"
- "sudo chmod +x /usr/local/share/chromedriver"
- "sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver"
- "bundle config set without 'development staging production'"
- "bundle config set deployment '[secure]'"
before_script:
- "cp config/application.yml.sample config/application.yml"
- "echo \"openssl_config_path: 'test/fixtures/files/test_ca/openssl.cnf'\" >> config/application.yml"
- "echo \"crl_dir: 'test/fixtures/files/test_ca/crl'\" >> config/application.yml"
- "echo \"crl_path: 'test/fixtures/files/test_ca/crl/crl.pem'\" >> config/application.yml"
- "echo \"ca_cert_path: 'test/fixtures/files/test_ca/certs/ca.crt.pem'\" >> config/application.yml"
- "echo \"ca_key_path: 'test/fixtures/files/test_ca/private/ca.key.pem'\" >> config/application.yml"
- "echo \"ca_key_password: 'password'\" >> config/application.yml"
- "cp config/database_travis.yml config/database.yml"
- "bundle exec rake db:setup:all"
- "curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter"
- "chmod +x ./cc-test-reporter"
- "./cc-test-reporter before-build"
after_script:
- "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
script:
- "bundle exec rails test test/*"
services:
- postgresql
addons:
postgresql: "9.4"
chrome: stable

View file

@ -1,3 +1,42 @@
23.12.2020
* fix for REPP logging and registrar portal communication [#1782](https://github.com/internetee/registry/pull/1782)
22.12.2020
* SSL CA verification fix for Bulk renew [#1778](https://github.com/internetee/registry/pull/1778)
21.12.2020
* Bulk renew for REPP and registrar [#1763](https://github.com/internetee/registry/issues/1763)
17.12.2020
* New API for registering bounced emails [#1687](https://github.com/internetee/registry/pull/1687)
16.12.2020
* Refactored domain delete confirmation for interactors [#1769](https://github.com/internetee/registry/issues/1769)
15.12.2020
* Improved logic for domain list request in registrant API [#1750](https://github.com/internetee/registry/pull/1750)
* Refactored Whois update job for interactors [#1771](https://github.com/internetee/registry/issues/1771)
14.12.2020
* Refactored domain cron jobs for interactors [#1767](https://github.com/internetee/registry/issues/1767)
09.12.2020
* Refactored domain update confirm for interactors [#1760](https://github.com/internetee/registry/issues/1760)
08.12.2020
* Replaced Travis-CI with GitHub Actions [#1746](https://github.com/internetee/registry/pull/1746)
* Refactored domain delete for interactors [#1755](https://github.com/internetee/registry/issues/1755)
01.12.2020
* Refactored clientHold for interactors [#1751](https://github.com/internetee/registry/issues/1751)
* Fixed internal error on removing clientHold status when not present [#1766](https://github.com/internetee/registry/issues/1766)
30.11.2020
* Refactor - interactors moved to domain space [#1762](https://github.com/internetee/registry/pull/1762)
27.11.2020
* Refactored delete confirmation for interactors [#1753](https://github.com/internetee/registry/issues/1753)
24.11.2020
* Added subnet support for list of allowed IPs [#983](https://github.com/internetee/registry/issues/983)
* Added contact endpoint to Restful EPP API [#1580](https://github.com/internetee/registry/issues/1580)

View file

@ -73,15 +73,11 @@ gem 'e_invoice', github: 'internetee/e_invoice', branch: :master
gem 'lhv', github: 'internetee/lhv', branch: 'master'
gem 'domain_name'
gem 'haml', '~> 5.0'
gem 'rexml'
gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
gem 'directo', github: 'internetee/directo', branch: 'master'
group :development do
# deploy
gem 'listen', '3.2.1'
gem 'mina', '0.3.1' # for fast deployment
end
group :development, :test do
gem 'pry', '0.10.1'

View file

@ -250,9 +250,6 @@ GEM
kaminari-core (= 1.2.1)
kaminari-core (1.2.1)
libxml-ruby (3.2.0)
listen (3.2.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.4.2)
loofah (2.7.0)
crass (~> 1.0.2)
@ -266,9 +263,6 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512)
mimemagic (0.3.5)
mina (0.3.1)
open4 (~> 1.3.4)
rake
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.14.2)
@ -296,7 +290,6 @@ GEM
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
open4 (1.3.4)
openid_connect (1.2.0)
activemodel
attr_required (>= 1.0.0)
@ -370,9 +363,6 @@ GEM
activesupport (>= 5.2.1)
i18n
polyamorous (= 2.3.2)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rbtree3 (0.6.0)
regexp_parser (1.8.0)
request_store (1.5.0)
@ -385,6 +375,7 @@ GEM
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.2.4)
ruby2_keywords (0.0.2)
rubyzip (2.3.0)
sass-rails (6.0.0)
@ -519,8 +510,6 @@ DEPENDENCIES
jquery-ui-rails (= 5.0.5)
kaminari
lhv!
listen (= 3.2.1)
mina (= 0.3.1)
minitest (~> 5.14)
money-rails
nokogiri
@ -537,6 +526,7 @@ DEPENDENCIES
rails (~> 6.0)
ransack (~> 2.3)
rest-client
rexml
sass-rails
select2-rails (= 3.5.9.3)
selectize-rails (= 0.12.1)

View file

@ -0,0 +1,30 @@
module Admin
class BouncedMailAddressesController < BaseController
before_action :set_bounced_mail_address, only: %i[show destroy]
load_and_authorize_resource
# GET /bounced_mail_addresses
def index
@bounced_mail_addresses = BouncedMailAddress.all.order(created_at: :desc)
end
# GET /bounced_mail_addresses/1
def show; end
# DELETE /bounced_mail_addresses/1
def destroy
@bounced_mail_address.destroy
redirect_to(
admin_bounced_mail_addresses_url,
notice: 'Bounced mail address was successfully destroyed.'
)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_bounced_mail_address
@bounced_mail_address = BouncedMailAddress.find(params[:id])
end
end
end

View file

@ -10,6 +10,11 @@ module Api
head :unauthorized unless ip_allowed
end
def authenticate_shared_key
api_key = "Basic #{ENV['api_shared_key']}"
head(:unauthorized) unless api_key == request.authorization
end
def not_found_error
uuid = params['uuid']
json = { error: 'Not Found', uuid: uuid, message: 'Record not found' }

View file

@ -0,0 +1,25 @@
module Api
module V1
class BouncesController < BaseController
before_action :authenticate_shared_key
# POST api/v1/bounces/
def create
return head(:bad_request) unless bounce_params[:bounce][:bouncedRecipients].any?
BouncedMailAddress.record(bounce_params)
head(:created)
rescue ActionController::ParameterMissing
head(:bad_request)
end
def bounce_params
params.require(:data).require(:bounce).require(:bouncedRecipients).each do |r|
r.require(:emailAddress)
end
params.require(:data)
end
end
end
end

View file

@ -19,15 +19,16 @@ module Api
end
contacts = current_user_contacts.limit(limit).offset(offset)
serialized_contacts = contacts.collect { |contact| serialize_contact(contact) }
serialized_contacts = contacts.collect { |contact| serialize_contact(contact, false) }
render json: serialized_contacts
end
def show
contact = current_user_contacts.find_by(uuid: params[:uuid])
links = params[:links] == 'true'
if contact
render json: serialize_contact(contact)
render json: serialize_contact(contact, links)
else
render json: { errors: [{ base: ['Contact not found'] }] }, status: :not_found
end
@ -85,7 +86,7 @@ module Api
contact.registrar.notify(action)
end
render json: serialize_contact(contact)
render json: serialize_contact(contact, false)
end
private
@ -96,8 +97,8 @@ module Api
current_registrant_user.direct_contacts
end
def serialize_contact(contact)
Serializers::RegistrantApi::Contact.new(contact).to_json
def serialize_contact(contact, links)
Serializers::RegistrantApi::Contact.new(contact, links).to_json
end
end
end

View file

@ -7,6 +7,7 @@ module Api
def index
limit = params[:limit] || 200
offset = params[:offset] || 0
simple = params[:simple] == 'true' || false
if limit.to_i > 200 || limit.to_i < 1
render(json: { errors: [{ limit: ['parameter is out of range'] }] },
@ -18,21 +19,20 @@ module Api
status: :bad_request) && return
end
@domains = current_user_domains.limit(limit).offset(offset)
serialized_domains = @domains.map do |item|
serializer = Serializers::RegistrantApi::Domain.new(item)
domains = current_user_domains
serialized_domains = domains.limit(limit).offset(offset).map do |item|
serializer = Serializers::RegistrantApi::Domain.new(item, simplify: simple)
serializer.to_json
end
render json: serialized_domains
render json: { count: domains.count, domains: serialized_domains }
end
def show
@domain = current_user_domains.find_by(uuid: params[:uuid])
if @domain
serializer = Serializers::RegistrantApi::Domain.new(@domain)
serializer = Serializers::RegistrantApi::Domain.new(@domain, simplify: false)
render json: serializer.to_json
else
render json: { errors: [{ base: ['Domain not found'] }] }, status: :not_found

View file

@ -4,11 +4,38 @@ class Registrar
def new
authorize! :manage, :repp
@expire_date = Time.zone.now.to_date
render file: 'registrar/bulk_change/new', locals: { active_tab: default_tab }
end
def bulk_renew
authorize! :manage, :repp
set_form_data
if ready_to_renew?
res = ReppApi.bulk_renew(domain_ids_for_bulk_renew, params[:period],
current_registrar_user)
flash_message(JSON.parse(res))
else
flash[:notice] = nil
end
render file: 'registrar/bulk_change/new', locals: { active_tab: :bulk_renew }
end
private
def ready_to_renew?
domain_ids_for_bulk_renew.present? && params[:renew].present?
end
def set_form_data
@expire_date = params[:expire_date].to_date
@domains = domains_by_date(@expire_date)
@period = params[:period]
end
def available_contacts
current_registrar_user.registrar.contacts.order(:name).pluck(:name, :code)
end
@ -16,5 +43,27 @@ class Registrar
def default_tab
:technical_contact
end
def domains_scope
current_registrar_user.registrar.domains
end
def domains_by_date(date)
domains_scope.where('valid_to <= ?', date)
end
def domain_ids_for_bulk_renew
params.dig('domain_ids')&.reject { |id| id.blank? }
end
def renew_task(domains)
Domains::BulkRenew::Start.run(domains: domains,
period_element: @period,
registrar: current_registrar_user.registrar)
end
def flash_message(res)
flash[:notice] = res['code'] == 1000 ? t(:bulk_renew_completed) : res['message']
end
end
end

View file

@ -55,10 +55,12 @@ class Registrar
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
flash[:notice] = t '.transferred', count: parsed_response[:data].size
failed = parsed_response[:data][:failed].each(&:domain_name).join(', ')
flash[:notice] = t('.transferred', count: parsed_response[:data][:success].size,
failed: failed)
redirect_to registrar_domains_url
else
@api_errors = parsed_response[:errors]
@api_errors = parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :bulk_transfer }
end
else

View file

@ -49,12 +49,13 @@ class Registrar
if response.code == '200'
notices = [t('.replaced')]
notices << "#{t('.affected_domains')}: #{parsed_response[:affected_domains].join(', ')}"
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
flash[:notice] = notices
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@api_errors = parsed_response[:errors]
@api_errors = parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :nameserver }
end
end

View file

@ -62,6 +62,7 @@ class Registrar
def find_user_by_idc_and_allowed(idc)
return User.new unless idc
possible_users = ApiUser.where(identity_code: idc) || User.new
possible_users.each do |selected_user|
if selected_user.registrar.white_ips.registrar_area.include_ip?(request.ip)

View file

@ -43,16 +43,18 @@ class Registrar
if response.code == '200'
notices = [t('.replaced')]
notices << "#{t('.affected_domains')}: #{parsed_response[:affected_domains].join(', ')}"
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
if parsed_response[:skipped_domains]
notices << "#{t('.skipped_domains')}: #{parsed_response[:skipped_domains].join(', ')}"
if parsed_response[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: " \
"#{parsed_response[:data][:skipped_domains].join(', ')}"
end
flash[:notice] = notices
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@error = parsed_response[:error]
@error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact }
end
end

View file

@ -3,6 +3,7 @@ module Repp
class BaseController < ActionController::API
rescue_from ActiveRecord::RecordNotFound, with: :not_found_error
before_action :authenticate_user
before_action :validate_webclient_ca
before_action :check_ip_restriction
attr_reader :current_user
@ -93,15 +94,33 @@ module Repp
end
def check_ip_restriction
allowed = @current_user.registrar.api_ip_white?(request.ip)
return if allowed
return if webclient_request?
return if @current_user.registrar.api_ip_white?(request.ip)
@response = { code: 2202,
message: I18n.t('registrar.authorization.ip_not_allowed', ip: request.ip) }
render(json: @response, status: :unauthorized)
end
def webclient_request?
return if Rails.env.test?
ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
end
def validate_webclient_ca
return unless webclient_request?
request_name = request.env['HTTP_SSL_CLIENT_S_DN_CN']
webclient_cn = ENV['webclient_cert_common_name'] || 'webclient'
return if request_name == webclient_cn
@response = { code: 2202,
message: I18n.t('registrar.authorization.ip_not_allowed', ip: request.ip) }
render(json: @response, status: :unauthorized)
end
def not_found_error
@response = { code: 2303, message: 'Object does not exist' }
render(json: @response, status: :not_found)

View file

@ -0,0 +1,65 @@
module Repp
module V1
module Domains
class RenewsController < BaseController
before_action :validate_renew_period, only: [:bulk_renew]
before_action :select_renewable_domains, only: [:bulk_renew]
def bulk_renew
renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period])
return render_success(data: { updated_domains: @domains.map(&:name) }) if renew.valid?
@epp_errors << { code: 2002,
msg: renew.errors.keys.map { |k, _v| renew.errors[k] }.join(', ') }
handle_errors
end
private
def validate_renew_period
@epp_errors ||= []
periods = Depp::Domain::PERIODS.map { |p| p[1] }
return if periods.include? bulk_renew_params[:renew_period]
@epp_errors << { code: 2005, msg: 'Invalid renew period' }
end
def select_renewable_domains
@epp_errors ||= []
if bulk_renew_params[:domains].instance_of?(Array)
@domains = bulk_renew_domains
else
@epp_errors << { code: 2005, msg: 'Domains attribute must be an array' }
end
return handle_errors if @epp_errors.any?
end
def run_bulk_renew_task(domains, period)
::Domains::BulkRenew::Start.run(domains: domains, period_element: period,
registrar: current_user.registrar)
end
def bulk_renew_params
params do
params.require(%i[domains renew_period])
params.permit(:domains, :renew_period)
end
end
def bulk_renew_domains
@epp_errors ||= []
domains = []
bulk_renew_params[:domains].each do |idn|
domain = Epp::Domain.find_by(name: idn)
domains << domain if domain
@epp_errors << { code: 2304, msg: "Object does not exist: #{idn}" } unless domain
end
domains
end
end
end
end
end

View file

@ -1,7 +0,0 @@
module CancelForceDeleteInteraction
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to cancel ForceDelete on'
end
end

View file

@ -1,10 +0,0 @@
module CancelForceDeleteInteraction
class CancelForceDelete < Base
def execute
compose(RemoveForceDeleteStatuses, inputs)
compose(RestoreStatusesBeforeForceDelete, inputs)
compose(ClearForceDeleteData, inputs)
compose(NotifyRegistrar, inputs)
end
end
end

View file

@ -1,10 +0,0 @@
module CancelForceDeleteInteraction
class ClearForceDeleteData < Base
def execute
domain.force_delete_data = nil
domain.force_delete_date = nil
domain.force_delete_start = nil
domain.save(validate: false)
end
end
end

View file

@ -1,8 +0,0 @@
module CancelForceDeleteInteraction
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_cancelled',
domain_name: domain.name))
end
end
end

View file

@ -1,11 +0,0 @@
module CancelForceDeleteInteraction
class RemoveForceDeleteStatuses < Base
def execute
domain.statuses.delete(DomainStatus::FORCE_DELETE)
domain.statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
domain.statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
domain.statuses.delete(DomainStatus::CLIENT_HOLD)
domain.save(validate: false)
end
end
end

View file

@ -1,9 +0,0 @@
module CancelForceDeleteInteraction
class RestoreStatusesBeforeForceDelete < Base
def execute
domain.statuses = domain.statuses_before_force_delete
domain.statuses_before_force_delete = nil
domain.save(validate: false)
end
end
end

View file

@ -0,0 +1,62 @@
module Domains
module BulkRenew
class SingleDomainRenew < ActiveInteraction::Base
object :domain,
class: Epp::Domain
integer :period
string :unit
object :registrar
def execute
in_transaction_with_retries do
success = domain.renew(domain.valid_to, period, unit)
if success
check_balance
reduce_balance
else
add_error
end
end
end
def check_balance
compose(Domains::CheckBalance::SingleDomain,
domain: domain,
operation: 'renew',
period: period,
unit: unit)
end
def reduce_balance
domain_pricelist = domain.pricelist('renew', period, unit)
registrar.debit!(sum: domain_pricelist.price.amount,
description: "#{I18n.t('renew')} #{domain.name}",
activity_type: AccountActivity::RENEW,
price: domain_pricelist)
end
def in_transaction_with_retries
if Rails.env.test?
yield
else
transaction_wrapper { yield }
end
rescue ActiveRecord::StatementInvalid
sleep rand / 100
retry
end
def transaction_wrapper
ActiveRecord::Base.transaction(isolation: :serializable) do
yield if block_given?
end
end
private
def add_error
errors.add(:domain, I18n.t('domain_renew_error_for_domain', domain: domain.name))
end
end
end
end

View file

@ -0,0 +1,56 @@
module Domains
module BulkRenew
class Start < ActiveInteraction::Base
array :domains do
object class: Epp::Domain
end
string :period_element
object :registrar
def execute
if renewable?
domains.each do |domain|
task = run_task(domain)
manage_errors(task)
end
else
manage_errors(mass_check_balance)
end
end
private
def renewable?
mass_check_balance.valid? && mass_check_balance.result
end
def period
period_element.to_i.zero? ? 1 : period_element.to_i
end
def unit
period_element[-1] || 'y'
end
def mass_check_balance
Domains::CheckBalance::Mass.run(domains: domains,
operation: 'renew',
period: period,
unit: unit,
balance: registrar.balance)
end
def manage_errors(task)
task.errors.each { |k, v| errors.add(k, v) } unless task.valid?
errors.add(:domain, I18n.t('not_enough_funds')) unless task.result
end
def run_task(domain)
Domains::BulkRenew::SingleDomainRenew.run(domain: domain,
period: period,
unit: unit,
registrar: registrar)
end
end
end
end

View file

@ -0,0 +1,9 @@
module Domains
module CancelForceDelete
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to cancel ForceDelete on'
end
end
end

View file

@ -0,0 +1,12 @@
module Domains
module CancelForceDelete
class CancelForceDelete < Base
def execute
compose(RemoveForceDeleteStatuses, inputs)
compose(RestoreStatusesBeforeForceDelete, inputs)
compose(ClearForceDeleteData, inputs)
compose(NotifyRegistrar, inputs)
end
end
end
end

View file

@ -0,0 +1,12 @@
module Domains
module CancelForceDelete
class ClearForceDeleteData < Base
def execute
domain.force_delete_data = nil
domain.force_delete_date = nil
domain.force_delete_start = nil
domain.save(validate: false)
end
end
end
end

View file

@ -0,0 +1,10 @@
module Domains
module CancelForceDelete
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_cancelled',
domain_name: domain.name))
end
end
end
end

View file

@ -0,0 +1,13 @@
module Domains
module CancelForceDelete
class RemoveForceDeleteStatuses < Base
def execute
domain.statuses.delete(DomainStatus::FORCE_DELETE)
domain.statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
domain.statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
domain.statuses.delete(DomainStatus::CLIENT_HOLD)
domain.save(validate: false)
end
end
end
end

View file

@ -0,0 +1,11 @@
module Domains
module CancelForceDelete
class RestoreStatusesBeforeForceDelete < Base
def execute
domain.statuses = domain.statuses_before_force_delete
domain.statuses_before_force_delete = nil
domain.save(validate: false)
end
end
end
end

View file

@ -0,0 +1,33 @@
module Domains
module CheckBalance
class Mass < ActiveInteraction::Base
array :domains do
object class: Epp::Domain
end
string :operation
integer :period
string :unit
float :balance
attr_accessor :total_price
def execute
calculate_total_price
balance >= @total_price
end
def calculate_total_price
@total_price = 0
domains.each do |domain|
task = Domains::CheckBalance::SingleDomain.run(domain: domain,
operation: 'renew',
period: period,
unit: unit)
task.valid? ? @total_price += task.result : errors.merge!(task.errors)
end
end
end
end
end

View file

@ -0,0 +1,26 @@
module Domains
module CheckBalance
class SingleDomain < ActiveInteraction::Base
object :domain,
class: Epp::Domain
string :operation
integer :period
string :unit
def execute
return domain_pricelist.price.amount if domain_pricelist.try(:price)
errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain,
domain: domain.name))
false
end
private
def domain_pricelist
domain.pricelist(operation, period.try(:to_i), unit)
end
end
end
end

View file

@ -0,0 +1,10 @@
module Domains
module ClientHold
class Base < ActiveInteraction::Base
def to_stdout(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
end
end
end

View file

@ -0,0 +1,69 @@
module Domains
module ClientHold
class ProcessClientHold < Base
object :domain,
class: Domain,
description: 'Domain to set ClientHold on'
# rubocop:disable Metrics/AbcSize
def execute
notify_on_grace_period if should_notify_on_soft_force_delete?
return unless client_holdable?
domain.statuses << DomainStatus::CLIENT_HOLD
to_stdout("DomainCron.start_client_hold: #{domain.id} (#{domain.name}) #{domain.changes}\n")
domain.save(validate: false)
notify_client_hold
to_stdout("Successfully set client_hold on (#{domain.name})")
end
def notify_on_grace_period
domain.registrar.notifications.create!(text: I18n.t('grace_period_started_domain',
domain_name: domain.name,
date: domain.force_delete_start))
send_mail if domain.template_name.present?
domain.update(contact_notification_sent_date: Time.zone.today)
end
def notify_client_hold
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
def send_mail
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.template_name).deliver_now
end
def should_notify_on_soft_force_delete?
domain.force_delete_scheduled? && domain.contact_notification_sent_date.blank? &&
domain.force_delete_start.to_date <= Time.zone.now.to_date &&
domain.force_delete_type.to_sym == :soft &&
!domain.statuses.include?(DomainStatus::CLIENT_HOLD)
end
# rubocop:enable Metrics/AbcSize
def client_holdable?
domain.force_delete_scheduled? &&
!domain.statuses.include?(DomainStatus::CLIENT_HOLD) &&
domain.force_delete_start.present? &&
force_delete_lte_today && force_delete_lte_valid_date
end
def force_delete_lte_today
domain.force_delete_start + Setting.expire_warning_period.days <= Time.zone.now
end
def force_delete_lte_valid_date
domain.force_delete_start + Setting.expire_warning_period.days <= domain.valid_to
end
end
end
end

View file

@ -0,0 +1,17 @@
module Domains
module ClientHold
class SetClientHold < Base
def execute
to_stdout('Setting client_hold to domains\n')
::PaperTrail.request.whodunnit = "cron - #{self.class.name}"
::Domain.force_delete_scheduled.each do |domain|
Domains::ClientHold::ProcessClientHold.run(domain: domain)
end
to_stdout('All client_hold setting are done\n')
end
end
end
end

View file

@ -0,0 +1,9 @@
module Domains
module Delete
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to delete'
end
end
end

View file

@ -0,0 +1,13 @@
module Domains
module Delete
class DoDelete < Base
def execute
::PaperTrail.request.whodunnit = "interaction - #{self.class.name}"
WhoisRecord.where(domain_id: domain.id).destroy_all
domain.destroy
compose(Domains::Delete::NotifyRegistrar, inputs)
end
end
end
end

View file

@ -0,0 +1,14 @@
module Domains
module Delete
class NotifyRegistrar < Base
def execute
bye_bye = domain.versions.last
domain.registrar.notifications.create!(
text: "#{I18n.t(:domain_deleted)}: #{domain.name}",
attached_obj_id: bye_bye.id,
attached_obj_type: bye_bye.class.to_s
)
end
end
end
end

View file

@ -0,0 +1,53 @@
module Domains
module DeleteConfirm
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to confirm release'
string :action
string :initiator,
default: nil
validates :domain, :action, presence: true
validates :action, inclusion: { in: [RegistrantVerification::CONFIRMED,
RegistrantVerification::REJECTED] }
def raise_errors!(domain)
return unless domain.errors.any?
message = "domain #{domain.name} failed with errors #{domain.errors.full_messages}"
throw message
end
def notify_registrar(message_key)
domain.registrar.notifications.create!(
text: "#{I18n.t(message_key)}: #{domain.name}",
attached_obj_id: domain.id,
attached_obj_type: domain.class.to_s
)
end
def preclean_pendings
domain.registrant_verification_token = nil
domain.registrant_verification_asked_at = nil
end
def clean_pendings!
domain.is_admin = true
domain.registrant_verification_token = nil
domain.registrant_verification_asked_at = nil
domain.pending_json = {}
clear_statuses
domain.save
end
def clear_statuses
domain.statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
domain.statuses.delete(DomainStatus::PENDING_UPDATE)
domain.statuses.delete(DomainStatus::PENDING_DELETE)
domain.status_notes[DomainStatus::PENDING_UPDATE] = ''
domain.status_notes[DomainStatus::PENDING_DELETE] = ''
end
end
end
end

View file

@ -0,0 +1,17 @@
module Domains
module DeleteConfirm
class ProcessAction < Base
def execute
::PaperTrail.request.whodunnit = "interaction - #{self.class.name} - #{action} by"\
" #{initiator}"
case action
when RegistrantVerification::CONFIRMED
compose(ProcessDeleteConfirmed, inputs)
when RegistrantVerification::REJECTED
compose(ProcessDeleteRejected, inputs)
end
end
end
end
end

View file

@ -0,0 +1,50 @@
module Domains
module DeleteConfirm
class ProcessDeleteConfirmed < Base
def execute
notify_registrar(:poll_pending_delete_confirmed_by_registrant)
domain.apply_pending_delete!
raise_errors!(domain)
end
def apply_pending_delete!
preclean_pendings
clean_pendings!
DomainDeleteMailer.accepted(domain).deliver_now
domain.set_pending_delete!
end
def set_pending_delete!
unless domain.pending_deletable?
add_epp_error
return
end
domain.delete_date = delete_date
domain.statuses << DomainStatus::PENDING_DELETE
set_server_hold if server_holdable?
domain.save(validate: false)
end
def set_server_hold
domain.statuses << DomainStatus::SERVER_HOLD
domain.outzone_at = Time.current
end
def server_holdable?
return false if domain.statuses.include?(DomainStatus::SERVER_HOLD)
return false if domain.statuses.include?(DomainStatus::SERVER_MANUAL_INZONE)
true
end
def delete_date
Time.zone.today + Setting.redemption_grace_period.days + 1.day
end
def add_epp_error
domain.add_epp_error('2304', nil, nil, I18n.t(:object_status_prohibits_operation))
end
end
end
end

View file

@ -0,0 +1,32 @@
module Domains
module DeleteConfirm
class ProcessDeleteRejected < Base
def execute
domain.cancel_pending_delete
notify_registrar(:poll_pending_delete_rejected_by_registrant)
domain.save(validate: false)
raise_errors!(domain)
send_domain_delete_rejected_email
end
def send_domain_delete_rejected_email
if domain.registrant_verification_token.blank?
warn "EMAIL NOT DELIVERED: registrant_verification_token is missing for #{domain.name}"
elsif domain.registrant_verification_asked_at.blank?
warn "EMAIL NOT DELIVERED: registrant_verification_asked_at is missing for #{domain.name}"
else
send_email
end
end
def warn(message)
Rails.logger.warn(message)
end
def send_email
DomainDeleteMailer.rejected(domain).deliver_now
end
end
end
end

View file

@ -0,0 +1,24 @@
module Domains
module DeleteConfirmEmail
class SendRequest < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to send delete confirmation'
def execute
log
DomainDeleteMailer.confirmation_request(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_later
end
private
def log
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})"\
" to #{domain.registrant.email}"
Rails.logger.info(message)
end
end
end
end

View file

@ -0,0 +1,10 @@
module Domains
module ExpirePeriod
class Base < ActiveInteraction::Base
def to_stdout(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
end
end
end

View file

@ -0,0 +1,28 @@
module Domains
module ExpirePeriod
class ProcessExpired < Base
object :domain,
class: Domain,
description: 'Domain to set expiration'
def execute
set_graceful_expired
to_stdout("start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}")
saved = domain.save(validate: false)
DomainExpireEmailJob.enqueue(domain.id, run_at: send_time) if saved
end
def set_graceful_expired
domain.outzone_at = domain.expire_time + Domain.expire_warning_period
domain.delete_date = domain.outzone_at + Domain.redemption_grace_period
domain.statuses |= [DomainStatus::EXPIRED]
end
def send_time
domain.valid_to + Setting.expiration_reminder_mail.to_i.days
end
end
end
end

View file

@ -0,0 +1,19 @@
module Domains
module ExpirePeriod
class Start < Base
def execute
::PaperTrail.request.whodunnit = "cron - #{self.class.name}"
count = 0
Domain.expired.each do |domain|
next unless domain.expirable?
count += 1
Domains::ExpirePeriod::ProcessExpired.run(domain: domain)
end
to_stdout("Successfully expired #{count}")
end
end
end
end

View file

@ -0,0 +1,10 @@
module Domains
module ExpiredPendings
class Base < ActiveInteraction::Base
def to_stdout(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
end
end
end

View file

@ -0,0 +1,35 @@
module Domains
module ExpiredPendings
class CleanAll < Base
def execute
to_stdout('Clean expired domain pendings')
::PaperTrail.request.whodunnit = "cron - #{self.class.name}"
count = 0
expired_pending_domains.each do |domain|
log_error(domain) && next unless need_to_be_cleared?(domain)
count += 1
Domains::ExpiredPendings::ProcessClean.run(domain: domain)
end
to_stdout("Successfully cancelled #{count} domain pendings")
end
private
def need_to_be_cleared?(domain)
domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation?
end
def log_error(domain)
to_stdout("ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, "\
'but no pendingDelete/pendingUpdate state present!')
end
def expired_pending_domains
expire_at = Setting.expire_pending_confirmation.hours.ago
Domain.where('registrant_verification_asked_at <= ?', expire_at)
end
end
end
end

View file

@ -0,0 +1,60 @@
module Domains
module ExpiredPendings
class ProcessClean < Base
object :domain,
class: Domain
def execute
check_notify
clean_pendings
to_stdout("DomainCron.clean_expired_pendings: ##{domain.id} (#{domain.name})")
UpdateWhoisRecordJob.enqueue domain.name, 'domain'
end
private
def notify_pending_update
RegistrantChangeMailer.expired(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_later
end
def notify_pending_delete
DomainDeleteMailer.expired(domain).deliver_later
end
def clean_pendings
clean_verification_data
domain.pending_json = {}
clean_statuses
domain.save
end
def statuses_to_clean
[DomainStatus::PENDING_DELETE_CONFIRMATION,
DomainStatus::PENDING_UPDATE,
DomainStatus::PENDING_DELETE]
end
def clean_statuses
domain.statuses = domain.statuses - statuses_to_clean
domain.status_notes[DomainStatus::PENDING_UPDATE] = ''
domain.status_notes[DomainStatus::PENDING_DELETE] = ''
end
def clean_verification_data
domain.registrant_verification_token = nil
domain.registrant_verification_asked_at = nil
end
def check_notify
notify_pending_update if domain.pending_update?
return unless domain.pending_delete? || domain.pending_delete_confirmation?
notify_pending_delete
end
end
end
end

View file

@ -0,0 +1,17 @@
module Domains
module ForceDelete
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to set ForceDelete on'
symbol :type,
default: :fast_track,
description: 'Force delete type, might be :fast_track or :soft'
boolean :notify_by_email,
default: false,
description: 'Do we need to send email notification'
validates :type, inclusion: { in: %i[fast_track soft] }
end
end
end

View file

@ -0,0 +1,12 @@
module Domains
module ForceDelete
class CheckDiscarded < Base
def execute
return true unless domain.discarded?
message = 'Force delete procedure cannot be scheduled while a domain is discarded'
errors.add(:domain, message)
end
end
end
end

View file

@ -0,0 +1,23 @@
module Domains
module ForceDelete
class NotifyByEmail < Base
def execute
return unless notify_by_email
if type == :fast_track
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: domain.notification_template)
end
end
def send_email
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.notification_template).deliver_now
end
end
end
end

View file

@ -0,0 +1,12 @@
module Domains
module ForceDelete
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
end
end
end

View file

@ -0,0 +1,19 @@
module Domains
module ForceDelete
class PostSetProcess < Base
def execute
statuses = domain.statuses
# Stop all pending actions
statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER)
statuses.delete(DomainStatus::PENDING_RENEW)
statuses.delete(DomainStatus::PENDING_CREATE)
# Allow deletion
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
domain.save(validate: false)
end
end
end
end

View file

@ -0,0 +1,15 @@
module Domains
module ForceDelete
class PrepareDomain < Base
STATUSES_TO_SET = [DomainStatus::FORCE_DELETE,
DomainStatus::SERVER_RENEW_PROHIBITED,
DomainStatus::SERVER_TRANSFER_PROHIBITED].freeze
def execute
domain.statuses_before_force_delete = domain.statuses
domain.statuses |= STATUSES_TO_SET
domain.save(validate: false)
end
end
end
end

View file

@ -0,0 +1,14 @@
module Domains
module ForceDelete
class SetForceDelete < Base
def execute
compose(CheckDiscarded, inputs)
compose(PrepareDomain, inputs)
compose(SetStatus, inputs)
compose(PostSetProcess, inputs)
compose(NotifyRegistrar, inputs)
compose(NotifyByEmail, inputs)
end
end
end
end

View file

@ -0,0 +1,40 @@
module Domains
module ForceDelete
class SetStatus < Base
def execute
domain.force_delete_type = type
type == :fast_track ? force_delete_fast_track : force_delete_soft
domain.save(validate: false)
end
def force_delete_fast_track
domain.force_delete_date = Time.zone.today +
expire_warning_period_days +
redemption_grace_period_days
domain.force_delete_start = Time.zone.today + 1.day
end
def force_delete_soft
years = (domain.valid_to.to_date - Time.zone.today).to_i / 365
soft_forcedelete_dates(years) if years.positive?
end
private
def soft_forcedelete_dates(years)
domain.force_delete_start = domain.valid_to - years.years
domain.force_delete_date = domain.force_delete_start +
Setting.expire_warning_period.days +
Setting.redemption_grace_period.days
end
def redemption_grace_period_days
Setting.redemption_grace_period.days + 1.day
end
def expire_warning_period_days
Setting.expire_warning_period.days
end
end
end
end

View file

@ -0,0 +1,10 @@
module Domains
module RedemptionGracePeriod
class Base < ActiveInteraction::Base
def to_stdout(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
end
end
end

View file

@ -0,0 +1,20 @@
module Domains
module RedemptionGracePeriod
class ProcessGracePeriod < Base
object :domain,
class: Domain
def execute
domain.statuses << DomainStatus::SERVER_HOLD
to_stdout(process_msg)
domain.save(validate: false)
end
private
def process_msg
"start_redemption_grace_period: #{domain.id} (#{domain.name}) #{domain.changes}"
end
end
end
end

View file

@ -0,0 +1,20 @@
module Domains
module RedemptionGracePeriod
class Start < Base
def execute
to_stdout('Setting server_hold to domains')
::PaperTrail.request.whodunnit = "cron - #{self.class.name}"
count = 0
Domain.outzone_candidates.each do |domain|
next unless domain.server_holdable?
count += 1
Domains::RedemptionGracePeriod::ProcessGracePeriod.run(domain: domain)
end
to_stdout("Successfully set server_hold to #{count} of domains")
end
end
end
end

View file

@ -0,0 +1,53 @@
module Domains
module UpdateConfirm
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to confirm update'
string :action
string :initiator,
default: nil
validates :domain, :action, presence: true
validates :action, inclusion: { in: [RegistrantVerification::CONFIRMED,
RegistrantVerification::REJECTED] }
def raise_errors!(domain)
return unless domain.errors.any?
message = "domain #{domain.name} failed with errors #{domain.errors.full_messages}"
throw message
end
def notify_registrar(message_key)
domain.registrar.notifications.create!(
text: "#{I18n.t(message_key)}: #{domain.name}",
attached_obj_id: domain.id,
attached_obj_type: domain.class.to_s
)
end
def preclean_pendings
domain.registrant_verification_token = nil
domain.registrant_verification_asked_at = nil
end
def clean_pendings!
domain.is_admin = true
domain.registrant_verification_token = nil
domain.registrant_verification_asked_at = nil
domain.pending_json = {}
clear_statuses
domain.save
end
def clear_statuses
domain.statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
domain.statuses.delete(DomainStatus::PENDING_UPDATE)
domain.statuses.delete(DomainStatus::PENDING_DELETE)
domain.status_notes[DomainStatus::PENDING_UPDATE] = ''
domain.status_notes[DomainStatus::PENDING_DELETE] = ''
end
end
end
end

View file

@ -0,0 +1,17 @@
module Domains
module UpdateConfirm
class ProcessAction < Base
def execute
::PaperTrail.request.whodunnit = "interaction - #{self.class.name} - #{action} by"\
" #{initiator}"
case action
when RegistrantVerification::CONFIRMED
compose(ProcessUpdateConfirmed, inputs)
when RegistrantVerification::REJECTED
compose(ProcessUpdateRejected, inputs)
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Domains
module UpdateConfirm
class ProcessUpdateConfirmed < Base
def execute
ActiveRecord::Base.transaction do
old_registrant = domain.registrant
notify_registrar(:poll_pending_update_confirmed_by_registrant)
apply_pending_update!
raise_errors!(domain)
RegistrantChange.new(domain: domain, old_registrant: old_registrant).confirm
end
end
def apply_pending_update!
preclean_pendings
update_domain
clean_pendings!
WhoisRecord.find_by(domain_id: domain.id).save # need to reload model
end
def update_domain
user = ApiUser.find(domain.pending_json['current_user_id'])
frame = domain.pending_json['frame'] ? domain.pending_json['frame'].with_indifferent_access : {}
#self.statuses.delete(DomainStatus::PENDING_UPDATE)
domain.upid = user.registrar.id if user.registrar
domain.up_date = Time.zone.now
Actions::DomainUpdate.new(domain, frame, true).call
#save!
end
end
end
end

View file

@ -0,0 +1,18 @@
module Domains
module UpdateConfirm
class ProcessUpdateRejected < Base
def execute
ActiveRecord::Base.transaction do
RegistrantChangeMailer.rejected(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_now
notify_registrar(:poll_pending_update_rejected_by_registrant)
preclean_pendings
clean_pendings!
end
end
end
end
end

View file

@ -1,16 +0,0 @@
module ForceDeleteInteraction
class Base < ActiveInteraction::Base
object :domain,
class: Domain,
description: 'Domain to set ForceDelete on'
symbol :type,
default: :fast_track,
description: 'Force delete type, might be :fast_track or :soft'
boolean :notify_by_email,
default: false,
description: 'Do we need to send email notification'
validates :type, inclusion: { in: %i[fast_track soft] }
end
end

View file

@ -1,11 +0,0 @@
module ForceDeleteInteraction
class CheckDiscarded < Base
def execute
return true unless domain.discarded?
message = 'Force delete procedure cannot be scheduled while a domain is discarded'
errors.add(:domain, message)
end
end
end

View file

@ -1,21 +0,0 @@
module ForceDeleteInteraction
class NotifyByEmail < Base
def execute
return unless notify_by_email
if type == :fast_track
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: domain.notification_template)
end
end
def send_email
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.notification_template).deliver_now
end
end
end

View file

@ -1,10 +0,0 @@
module ForceDeleteInteraction
class NotifyRegistrar < Base
def execute
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
end
end

View file

@ -1,17 +0,0 @@
module ForceDeleteInteraction
class PostSetProcess < Base
def execute
statuses = domain.statuses
# Stop all pending actions
statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER)
statuses.delete(DomainStatus::PENDING_RENEW)
statuses.delete(DomainStatus::PENDING_CREATE)
# Allow deletion
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
domain.save(validate: false)
end
end
end

View file

@ -1,13 +0,0 @@
module ForceDeleteInteraction
class PrepareDomain < Base
STATUSES_TO_SET = [DomainStatus::FORCE_DELETE,
DomainStatus::SERVER_RENEW_PROHIBITED,
DomainStatus::SERVER_TRANSFER_PROHIBITED].freeze
def execute
domain.statuses_before_force_delete = domain.statuses
domain.statuses |= STATUSES_TO_SET
domain.save(validate: false)
end
end
end

View file

@ -1,12 +0,0 @@
module ForceDeleteInteraction
class SetForceDelete < Base
def execute
compose(CheckDiscarded, inputs)
compose(PrepareDomain, inputs)
compose(SetStatus, inputs)
compose(PostSetProcess, inputs)
compose(NotifyRegistrar, inputs)
compose(NotifyByEmail, inputs)
end
end
end

View file

@ -1,38 +0,0 @@
module ForceDeleteInteraction
class SetStatus < Base
def execute
domain.force_delete_type = type
type == :fast_track ? force_delete_fast_track : force_delete_soft
domain.save(validate: false)
end
def force_delete_fast_track
domain.force_delete_date = Time.zone.today +
expire_warning_period_days +
redemption_grace_period_days
domain.force_delete_start = Time.zone.today + 1.day
end
def force_delete_soft
years = (domain.valid_to.to_date - Time.zone.today).to_i / 365
soft_forcedelete_dates(years) if years.positive?
end
private
def soft_forcedelete_dates(years)
domain.force_delete_start = domain.valid_to - years.years
domain.force_delete_date = domain.force_delete_start +
Setting.expire_warning_period.days +
Setting.redemption_grace_period.days
end
def redemption_grace_period_days
Setting.redemption_grace_period.days + 1.day
end
def expire_warning_period_days
Setting.expire_warning_period.days
end
end
end

View file

@ -0,0 +1,48 @@
module Whois
class DeleteRecord < ActiveInteraction::Base
string :name
string :type
validates :type, inclusion: { in: %w[reserved blocked domain disputed zone] }
def execute
send "delete_#{type}", name
end
# 1. deleting own
# 2. trying to regenerate reserved in order domain is still in the list
def delete_domain(name)
WhoisRecord.where(name: name).destroy_all
BlockedDomain.find_by(name: name).try(:generate_data)
ReservedDomain.find_by(name: name).try(:generate_data)
Dispute.active.find_by(domain_name: name).try(:generate_data)
end
def delete_reserved(name)
remove_status_from_whois(domain_name: name, domain_status: 'Reserved')
end
def delete_blocked(name)
delete_reserved(name)
end
def delete_disputed(name)
return if Dispute.active.find_by(domain_name: name).present?
remove_status_from_whois(domain_name: name, domain_status: 'disputed')
end
def delete_zone(name)
WhoisRecord.where(name: name).destroy_all
Whois::Record.where(name: name).destroy_all
end
def remove_status_from_whois(domain_name:, domain_status:)
Whois::Record.where(name: domain_name).each do |r|
r.json['status'] = r.json['status'].delete_if { |status| status == domain_status }
r.json['status'].blank? ? r.destroy : r.save
end
end
end
end

View file

@ -0,0 +1,39 @@
module Whois
class Update < ActiveInteraction::Base
array :names
string :type
validates :type, inclusion: { in: %w[reserved blocked domain disputed zone] }
def execute
::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{type}"
klass = determine_class
Array(names).each do |name|
record = find_record(klass, name)
if record
Whois::UpdateRecord.run(record: record, type: type)
else
Whois::DeleteRecord.run(name: name, type: type)
end
end
end
private
def determine_class
case type
when 'reserved' then ReservedDomain
when 'blocked' then BlockedDomain
when 'domain' then Domain
when 'disputed' then Dispute.active
else DNS::Zone
end
end
def find_record(klass, name)
klass == DNS::Zone ? klass.find_by(origin: name) : klass.find_by(name: name)
end
end
end

View file

@ -0,0 +1,32 @@
module Whois
class UpdateRecord < ActiveInteraction::Base
interface :record
string :type
validates :type, inclusion: { in: %w[reserved blocked domain disputed zone] }
def execute
send "update_#{type}", record
end
def update_domain(domain)
domain.whois_record ? domain.whois_record.save : domain.create_whois_record
end
def update_reserved(record)
record.generate_data
end
def update_blocked(record)
update_reserved(record)
end
def update_disputed(record)
update_reserved(record)
end
def update_zone(record)
update_reserved(record)
end
end
end

View file

@ -0,0 +1,2 @@
class ApplicationJob < ActiveJob::Base
end

View file

@ -1,22 +0,0 @@
class DomainDeleteConfirmEmailJob < Que::Job
def run(domain_id)
domain = Domain.find(domain_id)
log(domain)
DomainDeleteMailer.confirmation_request(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_now
end
private
def log(domain)
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})" \
" to #{domain.registrant.email}"
logger.info(message)
end
def logger
Rails.logger
end
end

View file

@ -1,39 +1,11 @@
class DomainDeleteConfirmJob < Que::Job
def run(domain_id, action, initiator = nil)
::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}"
# it's recommended to keep transaction against job table as short as possible.
ActiveRecord::Base.transaction do
class DomainDeleteConfirmJob < ApplicationJob
queue_as :default
def perform(domain_id, action, initiator = nil)
domain = Epp::Domain.find(domain_id)
case action
when RegistrantVerification::CONFIRMED
domain.notify_registrar(:poll_pending_delete_confirmed_by_registrant)
domain.apply_pending_delete!
raise_errors!(domain)
when RegistrantVerification::REJECTED
domain.statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
domain.notify_registrar(:poll_pending_delete_rejected_by_registrant)
domain.cancel_pending_delete
domain.save(validate: false)
raise_errors!(domain)
if domain.registrant_verification_token.blank?
Rails.logger.warn "EMAIL NOT DELIVERED: registrant_verification_token is missing for #{domain.name}"
elsif domain.registrant_verification_asked_at.blank?
Rails.logger.warn "EMAIL NOT DELIVERED: registrant_verification_asked_at is missing for #{domain.name}"
else
DomainDeleteMailer.rejected(domain).deliver_now
end
end
destroy # it's best to destroy the job in the same transaction
end
end
def raise_errors!(domain)
throw "domain #{domain.name} failed with errors #{domain.errors.full_messages}" if domain.errors.any?
Domains::DeleteConfirm::ProcessAction.run(domain: domain,
action: action,
initiator: initiator)
end
end

View file

@ -3,15 +3,6 @@ class DomainDeleteJob < Que::Job
def run(domain_id)
domain = Domain.find(domain_id)
::PaperTrail.request.whodunnit = "job - #{self.class.name}"
WhoisRecord.where(domain_id: domain.id).destroy_all
domain.destroy
bye_bye = domain.versions.last
domain.registrar.notifications.create!(
text: "#{I18n.t(:domain_deleted)}: #{domain.name}",
attached_obj_id: bye_bye.id,
attached_obj_type: bye_bye.class.to_s
)
Domains::Delete::DoDelete.run(domain: domain)
end
end

View file

@ -1,37 +1,10 @@
class DomainUpdateConfirmJob < Que::Job
def run(domain_id, action, initiator = nil)
::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}"
# it's recommended to keep transaction against job table as short as possible.
ActiveRecord::Base.transaction do
class DomainUpdateConfirmJob < ApplicationJob
queue_as :default
def perform(domain_id, action, initiator = nil)
domain = Epp::Domain.find(domain_id)
domain.is_admin = true
case action
when RegistrantVerification::CONFIRMED
old_registrant = domain.registrant
domain.notify_registrar(:poll_pending_update_confirmed_by_registrant)
raise_errors!(domain)
domain.apply_pending_update!
raise_errors!(domain)
domain.clean_pendings!
raise_errors!(domain)
RegistrantChange.new(domain: domain, old_registrant: old_registrant).confirm
when RegistrantVerification::REJECTED
RegistrantChangeMailer.rejected(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant).deliver_now
domain.notify_registrar(:poll_pending_update_rejected_by_registrant)
domain.preclean_pendings
domain.clean_pendings!
end
destroy # it's best to destroy the job in the same transaction
end
end
def raise_errors!(domain)
throw "domain #{domain.name} failed with errors #{domain.errors.full_messages}" if domain.errors.any?
Domains::UpdateConfirm::ProcessAction.run(domain: domain,
action: action,
initiator: initiator)
end
end

View file

@ -1,87 +1,5 @@
class UpdateWhoisRecordJob < Que::Job
def run(names, type)
::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{type}"
klass = determine_class(type)
Array(names).each do |name|
record = find_record(klass, name)
if record
send "update_#{type}", record
else
send "delete_#{type}", name
end
end
end
def find_record(klass, name)
klass == DNS::Zone ? klass.find_by(origin: name) : klass.find_by(name: name)
end
def determine_class(type)
case type
when 'reserved' then ReservedDomain
when 'blocked' then BlockedDomain
when 'domain' then Domain
when 'disputed' then Dispute.active
when 'zone' then DNS::Zone
end
end
def update_domain(domain)
domain.whois_record ? domain.whois_record.save : domain.create_whois_record
end
def update_reserved(record)
record.generate_data
end
def update_blocked(record)
update_reserved(record)
end
def update_disputed(record)
update_reserved(record)
end
def update_zone(record)
update_reserved(record)
end
# 1. deleting own
# 2. trying to regenerate reserved in order domain is still in the list
def delete_domain(name)
WhoisRecord.where(name: name).destroy_all
BlockedDomain.find_by(name: name).try(:generate_data)
ReservedDomain.find_by(name: name).try(:generate_data)
Dispute.active.find_by(domain_name: name).try(:generate_data)
end
def delete_reserved(name)
remove_status_from_whois(domain_name: name, domain_status: 'Reserved')
end
def delete_blocked(name)
delete_reserved(name)
end
def delete_disputed(name)
return if Dispute.active.find_by(domain_name: name).present?
remove_status_from_whois(domain_name: name, domain_status: 'disputed')
end
def delete_zone(name)
WhoisRecord.where(name: name).destroy_all
Whois::Record.where(name: name).destroy_all
end
def remove_status_from_whois(domain_name:, domain_status:)
Whois::Record.where(name: domain_name).each do |r|
r.json['status'] = r.json['status'].delete_if { |status| status == domain_status }
r.json['status'].blank? ? r.destroy : r.save
end
Whois::Update.run(names: [names].flatten, type: type)
end
end

View file

@ -109,6 +109,7 @@ class Ability
can :destroy, :pending
can :create, :zonefile
can :access, :settings_menu
can :manage, BouncedMailAddress
end
def static_registrant

View file

@ -169,16 +169,19 @@ module Actions
invalid = false
params[:statuses].each do |s|
unless DomainStatus::CLIENT_STATUSES.include?(s[:status])
domain.add_epp_error('2303', 'status', s[:status], %i[domain_statuses not_found])
domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found])
invalid = true
end
end
return if invalid
params[:statuses].select { |s| s[:action] == 'rem' }.each do |s|
if domain.statuses.include?(s[:status])
rem << s[:status]
else
domain.add_epp_error('2303', 'status', s[:status], %i[domain_statuses not_found])
STDOUT << 'AAAAAH'
domain.add_epp_error('2303', 'status', s[:status], %i[statuses not_found])
invalid = true
end
end

View file

@ -0,0 +1,28 @@
class BouncedMailAddress < ApplicationRecord
validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true
def bounce_reason
"#{action} (#{status} #{diagnostic})"
end
def self.record(json)
bounced_records = json['bounce']['bouncedRecipients']
bounced_records.each do |record|
bounce_record = BouncedMailAddress.new(params_from_json(json, record))
bounce_record.save
end
end
def self.params_from_json(json, bounced_record)
{
email: bounced_record['emailAddress'],
message_id: json['mail']['messageId'],
bounce_type: json['bounce']['bounceType'],
bounce_subtype: json['bounce']['bounceSubType'],
action: bounced_record['action'],
status: bounced_record['status'],
diagnostic: bounced_record['diagnosticCode'],
}
end
end

View file

@ -20,6 +20,6 @@ module Concerns::Domain::Deletable
end
def deletion_deadline
delete_date + 24.hours
(delete_date || Time.zone.now) + 24.hours
end
end

View file

@ -33,33 +33,14 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
statuses.include?(DomainStatus::FORCE_DELETE)
end
def should_notify_on_soft_force_delete?
force_delete_scheduled? && contact_notification_sent_date.blank? &&
force_delete_start.to_date <= Time.zone.now.to_date && force_delete_type.to_sym == :soft &&
!statuses.include?(DomainStatus::CLIENT_HOLD)
end
def client_holdable?
force_delete_scheduled? && !statuses.include?(DomainStatus::CLIENT_HOLD) &&
force_delete_start.present? && force_delete_lte_today && force_delete_lte_valid_date
end
def force_delete_lte_today
force_delete_start + Setting.expire_warning_period.days <= Time.zone.now
end
def force_delete_lte_valid_date
force_delete_start + Setting.expire_warning_period.days <= valid_to
end
def schedule_force_delete(type: :fast_track, notify_by_email: false)
ForceDeleteInteraction::SetForceDelete.run(domain: self,
Domains::ForceDelete::SetForceDelete.run(domain: self,
type: type,
notify_by_email: notify_by_email)
end
def cancel_force_delete
CancelForceDeleteInteraction::CancelForceDelete.run(domain: self)
Domains::CancelForceDelete::CancelForceDelete.run(domain: self)
end
def outzone_date

View file

@ -1,34 +0,0 @@
module Concerns
module Job
module ForceDelete
extend ActiveSupport::Concern
class_methods do
def start_client_hold
log_prepare_client_hold
::PaperTrail.request.whodunnit = "cron - #{__method__}"
::Domain.force_delete_scheduled.each do |domain|
proceed_client_hold(domain: domain)
end
log_end_end_force_delete_job
end
def proceed_client_hold(domain:)
notify_on_grace_period(domain) if domain.should_notify_on_soft_force_delete?
return unless domain.client_holdable?
domain.statuses << DomainStatus::CLIENT_HOLD
log_start_client_hold(domain)
domain.save(validate: false)
notify_client_hold(domain)
log_end_end_client_hold(domain)
end
end
end
end
end

View file

@ -1,34 +0,0 @@
module Concerns
module Job
module ForceDeleteLogging
extend ActiveSupport::Concern
class_methods do
def log_prepare_client_hold
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - Setting client_hold to domains\n"
end
def log_start_client_hold(domain)
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} DomainCron.start_client_hold: ##{domain.id} "\
"(#{domain.name}) #{domain.changes}\n"
end
def log_end_end_client_hold(domain)
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - Successfully set client_hold on (#{domain.name})"
end
def log_end_end_force_delete_job
return if Rails.env.test?
STDOUT << "#{Time.zone.now.utc} - All client_hold setting are done\n"
end
end
end
end
end

View file

@ -1,31 +0,0 @@
module Concerns
module Job
module ForceDeleteNotify
extend ActiveSupport::Concern
class_methods do
def notify_client_hold(domain)
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date))
end
def notify_on_grace_period(domain)
domain.registrar.notifications.create!(text: I18n.t('grace_period_started_domain',
domain_name: domain.name,
date: domain.force_delete_start))
send_mail(domain) if domain.template_name.present?
domain.update(contact_notification_sent_date: Time.zone.today)
end
def send_mail(domain)
DomainDeleteMailer.forced(domain: domain,
registrar: domain.registrar,
registrant: domain.registrant,
template_name: domain.template_name).deliver_now
end
end
end
end
end

View file

@ -347,19 +347,24 @@ class Contact < ApplicationRecord
@desc = {}
registrant_domains.each do |dom|
@desc[dom.name] ||= []
@desc[dom.name] << :registrant
@desc[dom.name] ||= { id: dom.uuid, roles: [] }
@desc[dom.name][:roles] << :registrant
end
domain_contacts.each do |dc|
@desc[dc.domain.name] ||= []
@desc[dc.domain.name] << dc.name.downcase.to_sym
@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
end
@desc
end
def related_domains
a = related_domain_descriptions
a.keys.map { |d| { name: d, id: a[d][:id], roles: a[d][:roles] } }
end
def status_notes_array=(notes)
self.status_notes = {}
notes ||= []

View file

@ -327,6 +327,7 @@ class Domain < ApplicationRecord
end
def notify_registrar(message_key)
# TODO: To be deleted with DomainDeleteConfirm refactoring
registrar.notifications.create!(
text: "#{I18n.t(message_key)}: #{name}",
attached_obj_id: id,
@ -335,11 +336,13 @@ class Domain < ApplicationRecord
end
def preclean_pendings
# TODO: To be deleted with refactoring
self.registrant_verification_token = nil
self.registrant_verification_asked_at = nil
end
def clean_pendings!
# TODO: To be deleted with refactoring
preclean_pendings
self.pending_json = {}
statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
@ -418,7 +421,7 @@ class Domain < ApplicationRecord
pending_delete_confirmation!
save(validate: false) # should check if this did succeed
DomainDeleteConfirmEmailJob.enqueue(id)
Domains::DeleteConfirmEmail::SendRequest.run(domain: self)
end
def cancel_pending_delete
@ -482,12 +485,6 @@ class Domain < ApplicationRecord
Registrant.find_by(id: pending_json['new_registrant_id'])
end
def set_graceful_expired
self.outzone_at = expire_time + self.class.expire_warning_period
self.delete_date = outzone_at + self.class.redemption_grace_period
self.statuses |= [DomainStatus::EXPIRED]
end
def pending_update?
statuses.include?(DomainStatus::PENDING_UPDATE)
end

View file

@ -1,84 +1,17 @@
class DomainCron
include Concerns::Job::ForceDelete
include Concerns::Job::ForceDeleteLogging
include Concerns::Job::ForceDeleteNotify
def self.clean_expired_pendings
STDOUT << "#{Time.zone.now.utc} - Clean expired domain pendings\n" unless Rails.env.test?
::PaperTrail.request.whodunnit = "cron - #{__method__}"
expire_at = Setting.expire_pending_confirmation.hours.ago
count = 0
expired_pending_domains = Domain.where('registrant_verification_asked_at <= ?', expire_at)
expired_pending_domains.each do |domain|
unless domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation?
msg = "#{Time.zone.now.utc} - ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, " \
"but no pendingDelete/pendingUpdate state present!\n"
STDOUT << msg unless Rails.env.test?
next
end
count += 1
if domain.pending_update?
RegistrantChangeExpiredEmailJob.enqueue(domain.id)
end
if domain.pending_delete? || domain.pending_delete_confirmation?
DomainDeleteMailer.expired(domain).deliver_now
end
domain.preclean_pendings
domain.clean_pendings!
unless Rails.env.test?
STDOUT << "#{Time.zone.now.utc} DomainCron.clean_expired_pendings: ##{domain.id} (#{domain.name})\n"
end
UpdateWhoisRecordJob.enqueue domain.name, 'domain'
end
STDOUT << "#{Time.zone.now.utc} - Successfully cancelled #{count} domain pendings\n" unless Rails.env.test?
count
Domains::ExpiredPendings::CleanAll.run!
end
def self.start_expire_period
::PaperTrail.request.whodunnit = "cron - #{__method__}"
domains = Domain.expired
marked = 0
real = 0
domains.each do |domain|
next unless domain.expirable?
real += 1
domain.set_graceful_expired
STDOUT << "#{Time.zone.now.utc} DomainCron.start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test?
send_time = domain.valid_to + Setting.expiration_reminder_mail.to_i.days
saved = domain.save(validate: false)
if saved
DomainExpireEmailJob.enqueue(domain.id, run_at: send_time)
marked += 1
end
end
STDOUT << "#{Time.zone.now.utc} - Successfully expired #{marked} of #{real} domains\n" unless Rails.env.test?
Domains::ExpirePeriod::Start.run!
end
def self.start_redemption_grace_period
STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test?
::PaperTrail.request.whodunnit = "cron - #{__method__}"
domains = Domain.outzone_candidates
marked = 0
real = 0
domains.each do |domain|
next unless domain.server_holdable?
real += 1
domain.statuses << DomainStatus::SERVER_HOLD
STDOUT << "#{Time.zone.now.utc} DomainCron.start_redemption_grace_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test?
domain.save(validate: false) and marked += 1
Domains::RedemptionGracePeriod::Start.run!
end
STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{marked} of #{real} domains\n" unless Rails.env.test?
marked
def self.start_client_hold
Domains::ClientHold::SetClientHold.run!
end
end

View file

@ -18,24 +18,24 @@ class RegistrantVerification < ApplicationRecord
def domain_registrant_change_confirm!(initiator)
self.action_type = DOMAIN_REGISTRANT_CHANGE
self.action = CONFIRMED
DomainUpdateConfirmJob.enqueue domain.id, CONFIRMED, initiator if save
DomainUpdateConfirmJob.perform_later domain.id, CONFIRMED, initiator if save
end
def domain_registrant_change_reject!(initiator)
self.action_type = DOMAIN_REGISTRANT_CHANGE
self.action = REJECTED
DomainUpdateConfirmJob.run domain.id, REJECTED, initiator if save
DomainUpdateConfirmJob.perform_later domain.id, REJECTED, initiator if save
end
def domain_registrant_delete_confirm!(initiator)
self.action_type = DOMAIN_DELETE
self.action = CONFIRMED
DomainDeleteConfirmJob.enqueue domain.id, CONFIRMED, initiator if save
DomainDeleteConfirmJob.perform_later domain.id, CONFIRMED, initiator if save
end
def domain_registrant_delete_reject!(initiator)
self.action_type = DOMAIN_DELETE
self.action = REJECTED
DomainDeleteConfirmJob.enqueue domain.id, REJECTED, initiator if save
DomainDeleteConfirmJob.perform_later domain.id, REJECTED, initiator if save
end
end

33
app/models/repp_api.rb Normal file
View file

@ -0,0 +1,33 @@
class ReppApi
def self.bulk_renew(domains, period, registrar)
payload = { domains: domains, renew_period: period }
uri = URI.parse("#{ENV['repp_url']}domains/renew/bulk")
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
req.body = payload.to_json
ReppApi.request(req, uri, registrar: registrar).body
end
def self.request(request, uri, registrar:)
request.basic_auth(registrar.username, registrar.plain_text_password) if registrar
client_cert = Rails.env.test? ? nil : File.read(ENV['cert_path'])
client_key = Rails.env.test? ? nil : File.read(ENV['key_path'])
params = ReppApi.compose_ca_auth_params(uri, client_cert, client_key)
Net::HTTP.start(uri.hostname, uri.port, params) do |http|
http.request(request)
end
end
def self.compose_ca_auth_params(uri, client_cert, client_key)
params = { use_ssl: (uri.scheme == 'https') }
params[:verify_mode] = OpenSSL::SSL::VERIFY_NONE if Rails.env.test? || Rails.env.development?
unless Rails.env.test?
params[:cert] = OpenSSL::X509::Certificate.new(client_cert)
params[:key] = OpenSSL::PKey::RSA.new(client_key)
end
params
end
end

View file

@ -5,19 +5,20 @@ class TechDomainContact < DomainContact
skipped_domains = []
tech_contacts = where(contact: current_contact)
transaction do
tech_contacts.each do |tech_contact|
if tech_contact.domain.discarded?
skipped_domains << tech_contact.domain.name
next
end
begin
tech_contact.contact = new_contact
tech_contact.save!
affected_domains << tech_contact.domain.name
rescue ActiveRecord::RecordNotUnique
skipped_domains << tech_contact.domain.name
end
end
return affected_domains.sort, skipped_domains.sort
[affected_domains.sort, skipped_domains.sort]
end
end

View file

@ -33,6 +33,7 @@
%li= link_to t('.blocked_domains'), admin_blocked_domains_path
%li= link_to t('.reserved_domains'), admin_reserved_domains_path
%li= link_to t('.disputed_domains'), admin_disputes_path
%li= link_to t('.bounced_email_addresses'), admin_bounced_mail_addresses_path
%li= link_to t('.epp_log'), admin_epp_logs_path(created_after: 'today')
%li= link_to t('.repp_log'), admin_repp_logs_path(created_after: 'today')
%li= link_to t('.que'), '/admin/que'

View file

@ -0,0 +1,36 @@
<h1>Bounced Mail Addresses</h1>
<div class="row">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-hover table-bordered table-condensed">
<thead>
<tr>
<th>Email</th>
<th>Action</th>
<th>Status</th>
<th>Diagnostic</th>
<th>Tracked</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tbody>
<% @bounced_mail_addresses.each do |mail_addr| %>
<tr>
<td><%= mail_addr.email %></td>
<td><%= mail_addr.action %></td>
<td><%= mail_addr.status %></td>
<td><%= mail_addr.diagnostic %></td>
<td><%= mail_addr.created_at %></td>
<td><%= link_to 'Detailed', admin_bounced_mail_address_path(mail_addr) %></td>
<td><%= link_to 'Destroy', admin_bounced_mail_address_path(mail_addr), method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,27 @@
<p>
<strong>Email:</strong>
<%= @bounced_mail_address.email %>
</p>
<p>
<strong>Bounced message ID:</strong>
<%= @bounced_mail_address.message_id %>
</p>
<p>
<strong>Overall bounce type:</strong>
<%= @bounced_mail_address.bounce_type %> (<%= @bounced_mail_address.bounce_subtype %> )
</p>
<p>
<strong>Bounced recipient status:</strong>
<%= @bounced_mail_address.action %> (<%= @bounced_mail_address.status %>)
</p>
<p>
<strong>Bounced recipient diagnostic:</strong>
<pre><%= @bounced_mail_address.diagnostic %></pre>
</p>
<%= link_to 'Back', admin_bounced_mail_addresses_path %>
<%= link_to 'Destroy', admin_bounced_mail_address_path(@bounced_mail_address), method: :delete, data: { confirm: 'Are you sure?' } %></td>

Some files were not shown because too many files have changed in this diff Show more