mirror of
https://github.com/internetee/registry.git
synced 2025-06-11 07:04:47 +02:00
Merge remote-tracking branch 'origin/master' into repp-domains
This commit is contained in:
commit
221e4ba578
140 changed files with 2575 additions and 731 deletions
|
@ -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
117
.github/workflows/ruby.yml
vendored
Normal 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
|
||||
|
35
.travis.yml
35
.travis.yml
|
@ -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
|
39
CHANGELOG.md
39
CHANGELOG.md
|
@ -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)
|
||||
|
|
6
Gemfile
6
Gemfile
|
@ -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'
|
||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -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)
|
||||
|
|
30
app/controllers/admin/bounced_mail_addresses_controller.rb
Normal file
30
app/controllers/admin/bounced_mail_addresses_controller.rb
Normal 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
|
|
@ -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' }
|
||||
|
|
25
app/controllers/api/v1/bounces_controller.rb
Normal file
25
app/controllers/api/v1/bounces_controller.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
65
app/controllers/repp/v1/domains/renews_controller.rb
Normal file
65
app/controllers/repp/v1/domains/renews_controller.rb
Normal 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
|
|
@ -1,7 +0,0 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class Base < ActiveInteraction::Base
|
||||
object :domain,
|
||||
class: Domain,
|
||||
description: 'Domain to cancel ForceDelete on'
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
62
app/interactions/domains/bulk_renew/single_domain_renew.rb
Normal file
62
app/interactions/domains/bulk_renew/single_domain_renew.rb
Normal 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
|
56
app/interactions/domains/bulk_renew/start.rb
Normal file
56
app/interactions/domains/bulk_renew/start.rb
Normal 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
|
9
app/interactions/domains/cancel_force_delete/base.rb
Normal file
9
app/interactions/domains/cancel_force_delete/base.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
33
app/interactions/domains/check_balance/mass.rb
Normal file
33
app/interactions/domains/check_balance/mass.rb
Normal 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
|
26
app/interactions/domains/check_balance/single_domain.rb
Normal file
26
app/interactions/domains/check_balance/single_domain.rb
Normal 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
|
10
app/interactions/domains/client_hold/base.rb
Normal file
10
app/interactions/domains/client_hold/base.rb
Normal 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
|
69
app/interactions/domains/client_hold/process_client_hold.rb
Normal file
69
app/interactions/domains/client_hold/process_client_hold.rb
Normal 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
|
17
app/interactions/domains/client_hold/set_client_hold.rb
Normal file
17
app/interactions/domains/client_hold/set_client_hold.rb
Normal 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
|
9
app/interactions/domains/delete/base.rb
Normal file
9
app/interactions/domains/delete/base.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module Domains
|
||||
module Delete
|
||||
class Base < ActiveInteraction::Base
|
||||
object :domain,
|
||||
class: Domain,
|
||||
description: 'Domain to delete'
|
||||
end
|
||||
end
|
||||
end
|
13
app/interactions/domains/delete/do_delete.rb
Normal file
13
app/interactions/domains/delete/do_delete.rb
Normal 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
|
14
app/interactions/domains/delete/notify_registrar.rb
Normal file
14
app/interactions/domains/delete/notify_registrar.rb
Normal 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
|
53
app/interactions/domains/delete_confirm/base.rb
Normal file
53
app/interactions/domains/delete_confirm/base.rb
Normal 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
|
17
app/interactions/domains/delete_confirm/process_action.rb
Normal file
17
app/interactions/domains/delete_confirm/process_action.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
10
app/interactions/domains/expire_period/base.rb
Normal file
10
app/interactions/domains/expire_period/base.rb
Normal 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
|
28
app/interactions/domains/expire_period/process_expired.rb
Normal file
28
app/interactions/domains/expire_period/process_expired.rb
Normal 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
|
19
app/interactions/domains/expire_period/start.rb
Normal file
19
app/interactions/domains/expire_period/start.rb
Normal 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
|
10
app/interactions/domains/expired_pendings/base.rb
Normal file
10
app/interactions/domains/expired_pendings/base.rb
Normal 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
|
35
app/interactions/domains/expired_pendings/clean_all.rb
Normal file
35
app/interactions/domains/expired_pendings/clean_all.rb
Normal 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
|
60
app/interactions/domains/expired_pendings/process_clean.rb
Normal file
60
app/interactions/domains/expired_pendings/process_clean.rb
Normal 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
|
17
app/interactions/domains/force_delete/base.rb
Normal file
17
app/interactions/domains/force_delete/base.rb
Normal 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
|
12
app/interactions/domains/force_delete/check_discarded.rb
Normal file
12
app/interactions/domains/force_delete/check_discarded.rb
Normal 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
|
23
app/interactions/domains/force_delete/notify_by_email.rb
Normal file
23
app/interactions/domains/force_delete/notify_by_email.rb
Normal 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
|
12
app/interactions/domains/force_delete/notify_registrar.rb
Normal file
12
app/interactions/domains/force_delete/notify_registrar.rb
Normal 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
|
19
app/interactions/domains/force_delete/post_set_process.rb
Normal file
19
app/interactions/domains/force_delete/post_set_process.rb
Normal 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
|
15
app/interactions/domains/force_delete/prepare_domain.rb
Normal file
15
app/interactions/domains/force_delete/prepare_domain.rb
Normal 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
|
14
app/interactions/domains/force_delete/set_force_delete.rb
Normal file
14
app/interactions/domains/force_delete/set_force_delete.rb
Normal 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
|
40
app/interactions/domains/force_delete/set_status.rb
Normal file
40
app/interactions/domains/force_delete/set_status.rb
Normal 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
|
10
app/interactions/domains/redemption_grace_period/base.rb
Normal file
10
app/interactions/domains/redemption_grace_period/base.rb
Normal 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
|
|
@ -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
|
20
app/interactions/domains/redemption_grace_period/start.rb
Normal file
20
app/interactions/domains/redemption_grace_period/start.rb
Normal 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
|
53
app/interactions/domains/update_confirm/base.rb
Normal file
53
app/interactions/domains/update_confirm/base.rb
Normal 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
|
17
app/interactions/domains/update_confirm/process_action.rb
Normal file
17
app/interactions/domains/update_confirm/process_action.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
48
app/interactions/whois/delete_record.rb
Normal file
48
app/interactions/whois/delete_record.rb
Normal 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
|
39
app/interactions/whois/update.rb
Normal file
39
app/interactions/whois/update.rb
Normal 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
|
32
app/interactions/whois/update_record.rb
Normal file
32
app/interactions/whois/update_record.rb
Normal 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
|
2
app/jobs/application_job.rb
Normal file
2
app/jobs/application_job.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class ApplicationJob < ActiveJob::Base
|
||||
end
|
|
@ -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
|
|
@ -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
|
||||
domain = Epp::Domain.find(domain_id)
|
||||
class DomainDeleteConfirmJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
case action
|
||||
when RegistrantVerification::CONFIRMED
|
||||
domain.notify_registrar(:poll_pending_delete_confirmed_by_registrant)
|
||||
domain.apply_pending_delete!
|
||||
raise_errors!(domain)
|
||||
def perform(domain_id, action, initiator = nil)
|
||||
domain = Epp::Domain.find(domain_id)
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
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)
|
||||
class DomainUpdateConfirmJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
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?
|
||||
def perform(domain_id, action, initiator = nil)
|
||||
domain = Epp::Domain.find(domain_id)
|
||||
Domains::UpdateConfirm::ProcessAction.run(domain: domain,
|
||||
action: action,
|
||||
initiator: initiator)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -109,6 +109,7 @@ class Ability
|
|||
can :destroy, :pending
|
||||
can :create, :zonefile
|
||||
can :access, :settings_menu
|
||||
can :manage, BouncedMailAddress
|
||||
end
|
||||
|
||||
def static_registrant
|
||||
|
|
|
@ -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
|
||||
|
|
28
app/models/bounced_mail_address.rb
Normal file
28
app/models/bounced_mail_address.rb
Normal 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
|
|
@ -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
|
||||
end
|
||||
|
|
|
@ -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,
|
||||
type: type,
|
||||
notify_by_email: notify_by_email)
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 ||= []
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
Domains::RedemptionGracePeriod::Start.run!
|
||||
end
|
||||
|
||||
::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
|
||||
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
|
||||
|
|
|
@ -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
33
app/models/repp_api.rb
Normal 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
|
|
@ -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
|
||||
|
||||
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
|
||||
|
|
|
@ -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'
|
||||
|
|
36
app/views/admin/bounced_mail_addresses/index.html.erb
Normal file
36
app/views/admin/bounced_mail_addresses/index.html.erb
Normal 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>
|
27
app/views/admin/bounced_mail_addresses/show.html.erb
Normal file
27
app/views/admin/bounced_mail_addresses/show.html.erb
Normal 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
Loading…
Add table
Add a link
Reference in a new issue