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

This commit is contained in:
Karl Erik Õunapuu 2021-01-11 16:01:55 +02:00
commit 70759cb51b
No known key found for this signature in database
GPG key ID: C9DD647298A34764
24 changed files with 331 additions and 28 deletions

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
module Admin
class MassActionsController < BaseController
before_action :authorize_admin
# GET /admin/mass_actions
def index; end
# POST /admin/mass_actions
def create
res = MassAction.process(params[:mass_action], params[:entry_list].path)
notice = if res
"#{params[:mass_action]} completed for #{res[:ok]}.\n" \
"Failed: #{res[:fail]}"
else
"Dataset integrity validation failed for #{params[:mass_action]}"
end
redirect_to(admin_mass_actions_path, notice: notice)
end
def authorize_admin
authorize! :manage, :mass_actions
end
end
end

View file

@ -48,18 +48,25 @@ class Registrar
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
notices = [t('.replaced')]
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
redirect_to(registrar_domains_url,
flash: { notice: compose_notice_message(parsed_response) })
else
@api_errors = parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :nameserver }
end
end
def compose_notice_message(res)
notices = ["#{t('.replaced')}. #{t('.affected_domains')}: " \
"#{res[:data][:affected_domains].join(', ')}"]
if res[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: #{res[:data][:skipped_domains].join(', ')}"
end
notices.join(', ')
end
def domain_list_from_csv
return [] if params[:puny_file].blank?

View file

@ -5,25 +5,31 @@ module Repp
before_action :verify_nameserver_existance, only: %i[update]
def update
domains = params[:data][:domains] || []
affected = current_user.registrar
.replace_nameservers(hostname,
hostname_params[:data][:attributes],
domains: domains)
affected, errored = current_user.registrar
.replace_nameservers(hostname,
hostname_params[:data][:attributes],
domains: domains_from_params)
render_success(data: data_format_for_success(affected))
render_success(data: data_format_for_success(affected, errored))
rescue ActiveRecord::RecordInvalid => e
handle_errors(e.record)
end
private
def data_format_for_success(affected_domains)
def domains_from_params
return [] unless params[:data][:domains]
params[:data][:domains].map(&:downcase)
end
def data_format_for_success(affected_domains, errored_domains)
{
type: 'nameserver',
id: params[:data][:attributes][:hostname],
attributes: params[:data][:attributes],
affected_domains: affected_domains,
skipped_domains: errored_domains,
}
end

View file

@ -10,6 +10,9 @@ module Domains
boolean :notify_by_email,
default: false,
description: 'Do we need to send email notification'
string :reason,
default: nil,
description: 'Which mail template to use explicitly'
validates :type, inclusion: { in: %i[fast_track soft] }
end

View file

@ -8,7 +8,7 @@ module Domains
send_email
domain.update(contact_notification_sent_date: Time.zone.today)
else
domain.update(template_name: domain.notification_template)
domain.update(template_name: domain.notification_template(explicit: reason))
end
end

View file

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

View file

@ -19,7 +19,10 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
end
end
def notification_template
def notification_template(explicit: nil)
reason = explicit&.downcase
return reason if %w[invalid_email invalid_phone].include?(reason)
if contact_emails_verification_failed.present?
'invalid_email'
elsif registrant.org?
@ -33,9 +36,8 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
statuses.include?(DomainStatus::FORCE_DELETE)
end
def schedule_force_delete(type: :fast_track, notify_by_email: false)
Domains::ForceDelete::SetForceDelete.run(domain: self,
type: type,
def schedule_force_delete(type: :fast_track, notify_by_email: false, reason: nil)
Domains::ForceDelete::SetForceDelete.run(domain: self, type: type, reason: reason,
notify_by_email: notify_by_email)
end

42
app/models/mass_action.rb Normal file
View file

@ -0,0 +1,42 @@
class MassAction
def self.process(action_type, entries)
entries = CSV.read(entries, headers: true)
case action_type
when 'force_delete'
process_force_delete(entries)
else
false
end
rescue StandardError
false
end
def self.process_force_delete(entries)
return false unless force_delete_entries_valid?(entries)
apply_force_deletes(entries)
end
def self.apply_force_deletes(entries)
log = { ok: [], fail: [] }
entries.each do |e|
dn = Domain.find_by(name_puny: e['domain_name'])
log[:fail] << e['domain_name'] and next unless dn
dn.schedule_force_delete(type: :soft, notify_by_email: true, reason: e['delete_reason'])
log[:ok] << dn.name
end
log
end
def self.force_delete_entries_valid?(entries)
entries.each do |e|
reasons = %w[ENTITY_BURIED INVALID_EMAIL INVALID_PHONE]
return false unless e['domain_name'].present? && reasons.include?(e['delete_reason'])
end
true
end
end

View file

@ -144,22 +144,33 @@ class Registrar < ApplicationRecord
# Audit log is needed, therefore no raw SQL
def replace_nameservers(hostname, new_attributes, domains: [])
transaction do
domain_scope = domains.dup
domain_list = []
failed_list = []
nameservers.where(hostname: hostname).find_each do |original_nameserver|
next unless domains.include?(original_nameserver.domain.name_puny) || domains.empty?
nameservers.where(hostname: hostname).find_each do |origin|
idn = origin.domain.name
puny = origin.domain.name_puny
next unless domains.include?(idn) || domains.include?(puny) || domains.empty?
if origin.domain.nameservers.where(hostname: new_attributes[:hostname]).any?
failed_list << idn
next
end
new_nameserver = Nameserver.new
new_nameserver.domain = original_nameserver.domain
new_nameserver.domain = origin.domain
new_nameserver.attributes = new_attributes
new_nameserver.save!
domain_list << original_nameserver.domain.name
domain_scope.delete_if { |i| i == idn || i == puny }
domain_list << idn
original_nameserver.destroy!
origin.destroy!
end
domain_list.uniq.sort
self.domains.where(name: domain_list).find_each(&:update_whois_record) if domain_list.any?
[domain_list.uniq.sort, (domain_scope + failed_list).uniq.sort]
end
end

View file

@ -33,6 +33,7 @@
%li= link_to t('.blocked_domains'), admin_blocked_domains_path
%li= link_to t('.reserved_domains'), admin_reserved_domains_path
%li= link_to t('.disputed_domains'), admin_disputes_path
%li= link_to t('.bulk_actions'), admin_mass_actions_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')

View file

@ -0,0 +1,19 @@
<div class="page-header">
<h1>Bulk actions</h1>
</div>
<div class="panel panel-default">
<div class="panel-heading">Bulk Domain Force Delete</div>
<div class="panel-body">
<p>Triggers <b>soft</b> force delete procedure for uploaded domain list. List must be in <b>CSV</b> format. First row of the CSV file must contain column headings with <b>domain_name</b> for the first and <b>delete_reason</b> for the second column. Each domain entry must be on separate line. Domain names are expected to be in punycode format, valid reasons are listed below.</p>
<p>Allowed delete reasons: <b>ENTITY_BURIED</b> | <b>INVALID_PHONE</b> | <b>INVALID_EMAIL</b></p>
<%= form_tag admin_mass_actions_path, multipart: true, method: :post do %>
<%= label_tag :entry_list %>
<%= file_field_tag :entry_list, required: true, accept: 'text/csv' %>
<%= hidden_field_tag :mass_action, 'force_delete' %>
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<br>
<%= submit_tag "Start force delete process", class: 'btn btn-danger', id: 'fd_submit' %>
<% end %>
</div>
</div>

View file

@ -0,0 +1,47 @@
<p>Lugupeetud domeeni <%= @domain.name %> registreerija/halduskontakt</p>
<p>Eesti Interneti Sihtasutusele (EIS) on saanud teatavaks, et domeeni <%= @domain.name %> kontakti(de) telefoni number või numbrid on puudulikud.</p>
<p>Et see olukord on vastuolus .ee <a href='https://www.internet.ee/domains/ee-domain-regulation'>domeenireeglitega</a> algatas EIS <%= @delete_period_length %> päeva pikkuse kustutusmenetluse. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav.</p>
<p>Andmete parandamiseks pöörduge palun oma registripidaja <%= @registrar.name %> poole või isiklike ja oma ettevõtte andmete puhul <a href="https://registrant.internet.ee/">registreerija portaali</a>.</p>
<p>Kui kontaktandmed ei ole <%= @delete_period_length %> päeva jooksul parandatud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile <a href="https://auction.internet.ee">.ee oksjonikeskkonda</a>. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe <a href="https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused">siit</a>.</p>
<p>Lisaküsimuste korral võtke palun ühendust oma registripidajaga:</p>
<%= render 'mailers/shared/registrar/registrar.et.html', registrar: @registrar %>
<%= render 'mailers/shared/signatures/signature.et.html' %>
<hr>
<p>Dear registrant/administrative contact of .ee domain,</p>
<p>Estonian Internet Foundation has learned that contact(s) phone number data of the domain <%= @domain.name %> are invalid.</p>
<p>Since this is a violation of <a href='https://www.internet.ee/domains/ee-domain-regulation'>Estonian domain regulations</a>, <%= @delete_period_length %>-day deletion process has started for the <%= @domain.name %> domain. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process.</p>
<p>Please, contact your registrar <%= @registrar.name %> with updated contact data, or in case of your personal or business data use <a href="https://registrant.internet.ee/">.ee portal for registrants</a></p>
<p>If the data is not fixed within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the <a href="https://auction.internet.ee">.ee auction environment</a>. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results <a href="https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment">here</a>.</p>
<p>Should you have additional questions, please contact your registrar:</p>
<%= render 'mailers/shared/registrar/registrar.en.html', registrar: @registrar %>
<%= render 'mailers/shared/signatures/signature.en.html' %>
<hr>
<p>Уважаемый регистрант/административный контакт домена .ee</p>
<p>Целевому учреждению Eesti Internet (EIS) стало известно, что контактные данные домена <%= @domain.name %> неверны - телефонные номера.</p>
<p>Так как это является нарушением <a href='https://www.internet.ee/domains/ee-domain-regulation'>Правил домена .ee</a>, <%= @delete_period_length %>-дневный процесс удаления начат для доменного имени <%= @domain.name %>. В течение первых <%= @expire_warning_period %> дней домен будет доступен в интернете.</p>
<p>Для уточнения контактных данных, пожалуйста, свяжитесь с регистратором <%= @registrar.name %>, либо воспользуйтесь <a href="https://registrant.internet.ee/">порталом для регистрантов</a></p>
<p>Если контактные данные не будут исправлены в течение <%= @delete_period_length %> дней, домен <%= @domain.name %> отправится <%= @domain.force_delete_date %> на доменный аукцион в <a href="https://auction.internet.ee">аукционной среде.ee</a>. Если в течение 24 часов в отношении домена <%= @domain.name %> е поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте <a href="https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment">здесь</a>.</p>
<p>В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором:
<%= render 'mailers/shared/registrar/registrar.ru.html', registrar: @registrar %></p>
<%= render 'mailers/shared/signatures/signature.ru.html' %>

View file

@ -0,0 +1,47 @@
<p>Lugupeetud domeeni <%= @domain.name %> registreerija/halduskontakt</p>
<p>Eesti Interneti Sihtasutusele (EIS) on saanud teatavaks, et domeeni <%= @domain.name %> kontakti(de) telefoni number või numbrid on puudulikud.</p>
<p>Et see olukord on vastuolus .ee <a href='https://www.internet.ee/domains/ee-domain-regulation'>domeenireeglitega</a> algatas EIS <%= @delete_period_length %> päeva pikkuse kustutusmenetluse. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav.</p>
<p>Andmete parandamiseks pöörduge palun oma registripidaja <%= @registrar.name %> poole või isiklike ja oma ettevõtte andmete puhul <a href="https://registrant.internet.ee/">registreerija portaali</a>.</p>
<p>Kui kontaktandmed ei ole <%= @delete_period_length %> päeva jooksul parandatud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile <a href="https://auction.internet.ee">.ee oksjonikeskkonda</a>. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe <a href="https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused">siit</a>.</p>
<p>Lisaküsimuste korral võtke palun ühendust oma registripidajaga:</p>
<%= render 'mailers/shared/registrar/registrar.et.html', registrar: @registrar %>
<%= render 'mailers/shared/signatures/signature.et.html' %>
<hr>
<p>Dear registrant/administrative contact of .ee domain,</p>
<p>Estonian Internet Foundation has learned that contact(s) phone number data of the domain <%= @domain.name %> are invalid.</p>
<p>Since this is a violation of <a href='https://www.internet.ee/domains/ee-domain-regulation'>Estonian domain regulations</a>, <%= @delete_period_length %>-day deletion process has started for the <%= @domain.name %> domain. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process.</p>
<p>Please, contact your registrar <%= @registrar.name %> with updated contact data, or in case of your personal or business data use <a href="https://registrant.internet.ee/">.ee portal for registrants</a></p>
<p>If the data is not fixed within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the <a href="https://auction.internet.ee">.ee auction environment</a>. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results <a href="https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment">here</a>.</p>
<p>Should you have additional questions, please contact your registrar:</p>
<%= render 'mailers/shared/registrar/registrar.en.html', registrar: @registrar %>
<%= render 'mailers/shared/signatures/signature.en.html' %>
<hr>
<p>Уважаемый регистрант/административный контакт домена .ee</p>
<p>Целевому учреждению Eesti Internet (EIS) стало известно, что контактные данные домена <%= @domain.name %> неверны - телефонные номера.</p>
<p>Так как это является нарушением <a href='https://www.internet.ee/domains/ee-domain-regulation'>Правил домена .ee</a>, <%= @delete_period_length %>-дневный процесс удаления начат для доменного имени <%= @domain.name %>. В течение первых <%= @expire_warning_period %> дней домен будет доступен в интернете.</p>
<p>Для уточнения контактных данных, пожалуйста, свяжитесь с регистратором <%= @registrar.name %>, либо воспользуйтесь <a href="https://registrant.internet.ee/">порталом для регистрантов</a></p>
<p>Если контактные данные не будут исправлены в течение <%= @delete_period_length %> дней, домен <%= @domain.name %> отправится <%= @domain.force_delete_date %> на доменный аукцион в <a href="https://auction.internet.ee">аукционной среде.ee</a>. Если в течение 24 часов в отношении домена <%= @domain.name %> е поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте <a href="https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment">здесь</a>.</p>
<p>В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором:
<%= render 'mailers/shared/registrar/registrar.ru.html', registrar: @registrar %></p>
<%= render 'mailers/shared/signatures/signature.ru.html' %>