From 0f3b033f790636c0209a1def1fb45665289a8084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 16 Sep 2020 15:59:02 +0300 Subject: [PATCH 001/106] Create bounced_mail_addresses table --- ...916125326_create_bounced_mail_addresses.rb | 12 ++++ db/structure.sql | 65 +++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20200916125326_create_bounced_mail_addresses.rb diff --git a/db/migrate/20200916125326_create_bounced_mail_addresses.rb b/db/migrate/20200916125326_create_bounced_mail_addresses.rb new file mode 100644 index 000000000..c6600afea --- /dev/null +++ b/db/migrate/20200916125326_create_bounced_mail_addresses.rb @@ -0,0 +1,12 @@ +class CreateBouncedMailAddresses < ActiveRecord::Migration[6.0] + def change + create_table :bounced_mail_addresses do |t| + t.string :email, null: false + t.string :bounce_reason, null: false + t.integer :incidents, null: false, default: 1 + t.jsonb :response_json + + t.timestamps + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 6a30fbc84..3ec055386 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -475,6 +475,40 @@ CREATE SEQUENCE public.blocked_domains_id_seq ALTER SEQUENCE public.blocked_domains_id_seq OWNED BY public.blocked_domains.id; +-- +-- Name: bounced_mail_addresses; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.bounced_mail_addresses ( + id bigint NOT NULL, + email character varying NOT NULL, + bounce_reason character varying NOT NULL, + incidents integer DEFAULT 1 NOT NULL, + response_json jsonb, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: bounced_mail_addresses_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.bounced_mail_addresses_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: bounced_mail_addresses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.bounced_mail_addresses_id_seq OWNED BY public.bounced_mail_addresses.id; + + -- -- Name: certificates; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1706,7 +1740,7 @@ ALTER SEQUENCE public.log_payment_orders_id_seq OWNED BY public.log_payment_orde -- --- Name: log_prices; Type: TABLE; Schema: public; Owner: - +-- Name: log_prices; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_prices ( @@ -1744,7 +1778,7 @@ ALTER SEQUENCE public.log_prices_id_seq OWNED BY public.log_prices.id; -- --- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: - +-- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_registrant_verifications ( @@ -2658,6 +2692,13 @@ ALTER TABLE ONLY public.bank_transactions ALTER COLUMN id SET DEFAULT nextval('p ALTER TABLE ONLY public.blocked_domains ALTER COLUMN id SET DEFAULT nextval('public.blocked_domains_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.bounced_mail_addresses ALTER COLUMN id SET DEFAULT nextval('public.bounced_mail_addresses_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2876,14 +2917,14 @@ ALTER TABLE ONLY public.log_payment_orders ALTER COLUMN id SET DEFAULT nextval(' -- --- Name: log_prices id; Type: DEFAULT; Schema: public; Owner: - +-- Name: id; Type: DEFAULT; Schema: public; Owner: - -- ALTER TABLE ONLY public.log_prices ALTER COLUMN id SET DEFAULT nextval('public.log_prices_id_seq'::regclass); -- --- Name: log_registrant_verifications id; Type: DEFAULT; Schema: public; Owner: - +-- Name: id; Type: DEFAULT; Schema: public; Owner: - -- ALTER TABLE ONLY public.log_registrant_verifications ALTER COLUMN id SET DEFAULT nextval('public.log_registrant_verifications_id_seq'::regclass); @@ -3100,6 +3141,14 @@ ALTER TABLE ONLY public.blocked_domains ADD CONSTRAINT blocked_domains_pkey PRIMARY KEY (id); +-- +-- Name: bounced_mail_addresses_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.bounced_mail_addresses + ADD CONSTRAINT bounced_mail_addresses_pkey PRIMARY KEY (id); + + -- -- Name: certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -3349,7 +3398,7 @@ ALTER TABLE ONLY public.log_payment_orders -- --- Name: log_prices log_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: log_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_prices @@ -3357,7 +3406,7 @@ ALTER TABLE ONLY public.log_prices -- --- Name: log_registrant_verifications log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_registrant_verifications @@ -4906,5 +4955,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200902131603'), ('20200908131554'), ('20200910085157'), -('20200910102028'); +('20200910102028'), +('20200916125326'); + From 188cca0c063325b91d641e808fbd3592a38f66eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 11:12:01 +0300 Subject: [PATCH 002/106] Create views for bounced emails --- .../bounced_mail_addresses_controller.rb | 60 +++++++++++++++++++ app/models/ability.rb | 1 + app/models/bounced_mail_address.rb | 2 + .../bounced_mail_addresses/_form.html.erb | 37 ++++++++++++ .../bounced_mail_addresses/edit.html.erb | 6 ++ .../bounced_mail_addresses/index.html.erb | 33 ++++++++++ .../admin/bounced_mail_addresses/new.html.erb | 5 ++ .../bounced_mail_addresses/show.html.erb | 24 ++++++++ config/routes.rb | 1 + 9 files changed, 169 insertions(+) create mode 100644 app/controllers/admin/bounced_mail_addresses_controller.rb create mode 100644 app/models/bounced_mail_address.rb create mode 100644 app/views/admin/bounced_mail_addresses/_form.html.erb create mode 100644 app/views/admin/bounced_mail_addresses/edit.html.erb create mode 100644 app/views/admin/bounced_mail_addresses/index.html.erb create mode 100644 app/views/admin/bounced_mail_addresses/new.html.erb create mode 100644 app/views/admin/bounced_mail_addresses/show.html.erb diff --git a/app/controllers/admin/bounced_mail_addresses_controller.rb b/app/controllers/admin/bounced_mail_addresses_controller.rb new file mode 100644 index 000000000..a33f90ab3 --- /dev/null +++ b/app/controllers/admin/bounced_mail_addresses_controller.rb @@ -0,0 +1,60 @@ +module Admin + class BouncedMailAddressesController < BaseController + before_action :set_bounced_mail_address, only: %i[show edit update destroy] + load_and_authorize_resource + + # GET /bounced_mail_addresses + def index + @bounced_mail_addresses = BouncedMailAddress.all + end + + # GET /bounced_mail_addresses/1 + def show; end + + # GET /bounced_mail_addresses/new + def new + @bounced_mail_address = BouncedMailAddress.new + end + + # GET /bounced_mail_addresses/1/edit + def edit; end + + # POST /bounced_mail_addresses + def create + @bounced_mail_address = BouncedMailAddress.new(bounced_mail_address_params) + + if @bounced_mail_address.save + redirect_to(admin_bounced_mail_addresses_url, notice: 'Bounced mail address was successfully created.') + else + render(:new) + end + end + + # PATCH/PUT /bounced_mail_addresses/1 + def update + if @bounced_mail_address.update(bounced_mail_address_params) + redirect_to(@bounced_mail_address, notice: 'Bounced mail address was successfully updated.') + else + render(:edit) + end + 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 + + # Only allow a trusted parameter "white list" through. + def bounced_mail_address_params + params.require(:bounced_mail_address).permit(:email, :bounce_reason, :incidents, :response_json) + end + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index dce8a515b..31637b8ea 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -109,6 +109,7 @@ class Ability can :destroy, :pending can :create, :zonefile can :access, :settings_menu + can :manage, BouncedMailAddress end def static_registrant diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb new file mode 100644 index 000000000..d8f6a037b --- /dev/null +++ b/app/models/bounced_mail_address.rb @@ -0,0 +1,2 @@ +class BouncedMailAddress < ApplicationRecord +end diff --git a/app/views/admin/bounced_mail_addresses/_form.html.erb b/app/views/admin/bounced_mail_addresses/_form.html.erb new file mode 100644 index 000000000..7a384bd3f --- /dev/null +++ b/app/views/admin/bounced_mail_addresses/_form.html.erb @@ -0,0 +1,37 @@ +<%= form_for([:admin, @bounced_mail_address], html: { class: 'form-horizontal' }) do |form| %> + <% if @bounced_mail_address.errors.any? %> +
+

<%= pluralize(bounced_mail_address.errors.count, "error") %> prohibited this bounced_mail_address from being saved:

+ +
    + <% @bounced_mail_address.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= form.label :email %> + <%= form.text_field :email %> +
+ +
+ <%= form.label :bounce_reason %> + <%= form.text_field :bounce_reason %> +
+ +
+ <%= form.label :incidents %> + <%= form.number_field :incidents %> +
+ +
+ <%= form.label :response_json %> + <%= form.text_field :response_json %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/app/views/admin/bounced_mail_addresses/edit.html.erb b/app/views/admin/bounced_mail_addresses/edit.html.erb new file mode 100644 index 000000000..a3dfe2d84 --- /dev/null +++ b/app/views/admin/bounced_mail_addresses/edit.html.erb @@ -0,0 +1,6 @@ +

Editing Bounced Mail Address

+ +<%= render 'form', bounced_mail_address: @bounced_mail_address %> + +<%= link_to 'Show', admin_bounced_mail_address_path(@bounced_mail_address)%> | +<%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/app/views/admin/bounced_mail_addresses/index.html.erb b/app/views/admin/bounced_mail_addresses/index.html.erb new file mode 100644 index 000000000..c2f95ca68 --- /dev/null +++ b/app/views/admin/bounced_mail_addresses/index.html.erb @@ -0,0 +1,33 @@ +

<%= notice %>

+ +

Bounced Mail Addresses

+ + + + + + + + + + + + + + <% @bounced_mail_addresses.each do |mail_addr| %> + + + + + + + + + + <% end %> + +
EmailBounce reasonIncidentsResponse json
<%= mail_addr.email %><%= mail_addr.bounce_reason %><%= mail_addr.incidents %><%= mail_addr.response_json %><%= link_to 'Show', admin_bounced_mail_address_path(mail_addr) %><%= link_to 'Edit', edit_admin_bounced_mail_address_path(mail_addr) %><%= link_to 'Destroy', admin_bounced_mail_address_path(mail_addr), method: :delete, data: { confirm: 'Are you sure?' } %>
+ +
+ +<%= link_to 'New Bounced Mail Address', new_admin_bounced_mail_address_path %> diff --git a/app/views/admin/bounced_mail_addresses/new.html.erb b/app/views/admin/bounced_mail_addresses/new.html.erb new file mode 100644 index 000000000..010ac79dc --- /dev/null +++ b/app/views/admin/bounced_mail_addresses/new.html.erb @@ -0,0 +1,5 @@ +

New Bounced Mail Address

+ +<%= render 'form', bounced_mail_address: @bounced_mail_address %> + +<%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/app/views/admin/bounced_mail_addresses/show.html.erb b/app/views/admin/bounced_mail_addresses/show.html.erb new file mode 100644 index 000000000..1f48ad5cf --- /dev/null +++ b/app/views/admin/bounced_mail_addresses/show.html.erb @@ -0,0 +1,24 @@ +

<%= notice %>

+ +

+ Email: + <%= @bounced_mail_address.email %> +

+ +

+ Bounce reason: + <%= @bounced_mail_address.bounce_reason %> +

+ +

+ Incidents: + <%= @bounced_mail_address.incidents %> +

+ +

+ Response json: + <%= @bounced_mail_address.response_json %> +

+ +<%= link_to 'Edit', edit_admin_bounced_mail_address_path(@bounced_mail_address) %> | +<%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/config/routes.rb b/config/routes.rb index 223cf3171..cdbd63f31 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -298,6 +298,7 @@ Rails.application.routes.draw do resources :delayed_jobs resources :epp_logs resources :repp_logs + resources :bounced_mail_addresses authenticate :admin_user do mount Que::Web, at: 'que' From 22f9c2058d137a021034030c66ac33f8049f17a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 11:55:52 +0300 Subject: [PATCH 003/106] Create api/v1/bounces endpoint --- app/controllers/api/v1/bounces_controller.rb | 12 ++++++++++++ config/routes.rb | 1 + 2 files changed, 13 insertions(+) create mode 100644 app/controllers/api/v1/bounces_controller.rb diff --git a/app/controllers/api/v1/bounces_controller.rb b/app/controllers/api/v1/bounces_controller.rb new file mode 100644 index 000000000..cff8c3efe --- /dev/null +++ b/app/controllers/api/v1/bounces_controller.rb @@ -0,0 +1,12 @@ +module Api + module V1 + class BouncesController < BaseController + before_action :authenticate + + def create + bounced_mail_address = BouncedMailAddress.record(json) + bounced_mail_address ? render(head: :ok) : render(head: :failed) + end + end + end +end diff --git a/config/routes.rb b/config/routes.rb index cdbd63f31..89f8f0cd6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -64,6 +64,7 @@ Rails.application.routes.draw do end resources :auctions, only: %i[index show update], param: :uuid + resources :bounces, only: %i[create] end match '*all', controller: 'cors', action: 'cors_preflight_check', via: [:options], From 140df0acf78a9e0139301649b244247c66b612e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 13:26:00 +0300 Subject: [PATCH 004/106] Fix CC issues --- .../admin/bounced_mail_addresses_controller.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/bounced_mail_addresses_controller.rb b/app/controllers/admin/bounced_mail_addresses_controller.rb index a33f90ab3..551413e2c 100644 --- a/app/controllers/admin/bounced_mail_addresses_controller.rb +++ b/app/controllers/admin/bounced_mail_addresses_controller.rb @@ -24,7 +24,10 @@ module Admin @bounced_mail_address = BouncedMailAddress.new(bounced_mail_address_params) if @bounced_mail_address.save - redirect_to(admin_bounced_mail_addresses_url, notice: 'Bounced mail address was successfully created.') + redirect_to( + admin_bounced_mail_addresses_url, + notice: 'Bounced mail address was successfully created.' + ) else render(:new) end @@ -42,7 +45,10 @@ module Admin # 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.') + redirect_to( + admin_bounced_mail_addresses_url, + notice: 'Bounced mail address was successfully destroyed.' + ) end private @@ -54,7 +60,12 @@ module Admin # Only allow a trusted parameter "white list" through. def bounced_mail_address_params - params.require(:bounced_mail_address).permit(:email, :bounce_reason, :incidents, :response_json) + params.require(:bounced_mail_address).permit( + :email, + :bounce_reason, + :incidents, + :response_json + ) end end end From 6af37a787dc56ec7b4d89079d6bf11d5ddf58651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 13:26:48 +0300 Subject: [PATCH 005/106] Restructure bounced mails view --- app/models/bounced_mail_address.rb | 22 +++++++ .../bounced_mail_addresses/index.html.erb | 61 ++++++++++--------- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index d8f6a037b..6609829da 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,2 +1,24 @@ class BouncedMailAddress < ApplicationRecord + validates :email, presence: true + validates :bounce_reason, presence: true + + def diagnostic + response_json['diagnosticCode'] + end + + def action + response_json['action'] + end + + def status + response_json['status'] + end + + def self.record(json) + bounced_records = json['bounce']['bouncedRecipients'] + bounced_records.each do |record| + bounce_record = BouncedMailAddress.new(email: record['emailAddress'], response_json: record) + bounce_record.save + end + end end diff --git a/app/views/admin/bounced_mail_addresses/index.html.erb b/app/views/admin/bounced_mail_addresses/index.html.erb index c2f95ca68..b6a019282 100644 --- a/app/views/admin/bounced_mail_addresses/index.html.erb +++ b/app/views/admin/bounced_mail_addresses/index.html.erb @@ -2,32 +2,37 @@

Bounced Mail Addresses

- - - - - - - - - - +
+
+
+
+
EmailBounce reasonIncidentsResponse json
+ + + + + + + + + + - - <% @bounced_mail_addresses.each do |mail_addr| %> - - - - - - - - - - <% end %> - -
EmailActionStatusDiagnosticTrackedActions
<%= mail_addr.email %><%= mail_addr.bounce_reason %><%= mail_addr.incidents %><%= mail_addr.response_json %><%= link_to 'Show', admin_bounced_mail_address_path(mail_addr) %><%= link_to 'Edit', edit_admin_bounced_mail_address_path(mail_addr) %><%= link_to 'Destroy', admin_bounced_mail_address_path(mail_addr), method: :delete, data: { confirm: 'Are you sure?' } %>
- -
- -<%= link_to 'New Bounced Mail Address', new_admin_bounced_mail_address_path %> + + <% @bounced_mail_addresses.each do |mail_addr| %> + + <%= mail_addr.email %> + <%= mail_addr.action %> + <%= mail_addr.status %> + <%= mail_addr.diagnostic %> + <%= mail_addr.created_at %> + <%= link_to 'Detailed', admin_bounced_mail_address_path(mail_addr) %> + <%= link_to 'Destroy', admin_bounced_mail_address_path(mail_addr), method: :delete, data: { confirm: 'Are you sure?' } %> + + <% end %> + + + + + + From 834b2c95bc7e56c2c4ba15a60d64f7cd9b89cbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 14:21:25 +0300 Subject: [PATCH 006/106] Add full request JSON to bounced mail, remove unused views --- .../bounced_mail_addresses_controller.rb | 35 +----------------- app/models/bounced_mail_address.rb | 15 ++++++-- app/views/admin/base/_menu.haml | 1 + .../bounced_mail_addresses/_form.html.erb | 37 ------------------- .../bounced_mail_addresses/edit.html.erb | 6 --- .../admin/bounced_mail_addresses/new.html.erb | 5 --- .../bounced_mail_addresses/show.html.erb | 10 +++-- config/locales/admin/menu.en.yml | 1 + ..._recipient_json_to_bounced_mail_address.rb | 5 +++ db/structure.sql | 6 ++- 10 files changed, 31 insertions(+), 90 deletions(-) delete mode 100644 app/views/admin/bounced_mail_addresses/_form.html.erb delete mode 100644 app/views/admin/bounced_mail_addresses/edit.html.erb delete mode 100644 app/views/admin/bounced_mail_addresses/new.html.erb create mode 100644 db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb diff --git a/app/controllers/admin/bounced_mail_addresses_controller.rb b/app/controllers/admin/bounced_mail_addresses_controller.rb index 551413e2c..da9421450 100644 --- a/app/controllers/admin/bounced_mail_addresses_controller.rb +++ b/app/controllers/admin/bounced_mail_addresses_controller.rb @@ -1,47 +1,16 @@ module Admin class BouncedMailAddressesController < BaseController - before_action :set_bounced_mail_address, only: %i[show edit update destroy] + 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 + @bounced_mail_addresses = BouncedMailAddress.all.order(created_at: :desc) end # GET /bounced_mail_addresses/1 def show; end - # GET /bounced_mail_addresses/new - def new - @bounced_mail_address = BouncedMailAddress.new - end - - # GET /bounced_mail_addresses/1/edit - def edit; end - - # POST /bounced_mail_addresses - def create - @bounced_mail_address = BouncedMailAddress.new(bounced_mail_address_params) - - if @bounced_mail_address.save - redirect_to( - admin_bounced_mail_addresses_url, - notice: 'Bounced mail address was successfully created.' - ) - else - render(:new) - end - end - - # PATCH/PUT /bounced_mail_addresses/1 - def update - if @bounced_mail_address.update(bounced_mail_address_params) - redirect_to(@bounced_mail_address, notice: 'Bounced mail address was successfully updated.') - else - render(:edit) - end - end - # DELETE /bounced_mail_addresses/1 def destroy @bounced_mail_address.destroy diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index 6609829da..78f37c374 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,23 +1,30 @@ class BouncedMailAddress < ApplicationRecord validates :email, presence: true validates :bounce_reason, presence: true + before_validation :assign_bounce_reason + + def assign_bounce_reason + self.bounce_reason = "#{action} (#{status} #{diagnostic})" + end def diagnostic - response_json['diagnosticCode'] + recipient_json['diagnosticCode'] end def action - response_json['action'] + recipient_json['action'] end def status - response_json['status'] + recipient_json['status'] end def self.record(json) bounced_records = json['bounce']['bouncedRecipients'] bounced_records.each do |record| - bounce_record = BouncedMailAddress.new(email: record['emailAddress'], response_json: record) + bounce_record = BouncedMailAddress.new(email: record['emailAddress'], recipient_json: record, + response_json: json) + bounce_record.save end end diff --git a/app/views/admin/base/_menu.haml b/app/views/admin/base/_menu.haml index a327419fd..5853bd3e6 100644 --- a/app/views/admin/base/_menu.haml +++ b/app/views/admin/base/_menu.haml @@ -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' diff --git a/app/views/admin/bounced_mail_addresses/_form.html.erb b/app/views/admin/bounced_mail_addresses/_form.html.erb deleted file mode 100644 index 7a384bd3f..000000000 --- a/app/views/admin/bounced_mail_addresses/_form.html.erb +++ /dev/null @@ -1,37 +0,0 @@ -<%= form_for([:admin, @bounced_mail_address], html: { class: 'form-horizontal' }) do |form| %> - <% if @bounced_mail_address.errors.any? %> -
-

<%= pluralize(bounced_mail_address.errors.count, "error") %> prohibited this bounced_mail_address from being saved:

- -
    - <% @bounced_mail_address.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
- <% end %> - -
- <%= form.label :email %> - <%= form.text_field :email %> -
- -
- <%= form.label :bounce_reason %> - <%= form.text_field :bounce_reason %> -
- -
- <%= form.label :incidents %> - <%= form.number_field :incidents %> -
- -
- <%= form.label :response_json %> - <%= form.text_field :response_json %> -
- -
- <%= form.submit %> -
-<% end %> diff --git a/app/views/admin/bounced_mail_addresses/edit.html.erb b/app/views/admin/bounced_mail_addresses/edit.html.erb deleted file mode 100644 index a3dfe2d84..000000000 --- a/app/views/admin/bounced_mail_addresses/edit.html.erb +++ /dev/null @@ -1,6 +0,0 @@ -

Editing Bounced Mail Address

- -<%= render 'form', bounced_mail_address: @bounced_mail_address %> - -<%= link_to 'Show', admin_bounced_mail_address_path(@bounced_mail_address)%> | -<%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/app/views/admin/bounced_mail_addresses/new.html.erb b/app/views/admin/bounced_mail_addresses/new.html.erb deleted file mode 100644 index 010ac79dc..000000000 --- a/app/views/admin/bounced_mail_addresses/new.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -

New Bounced Mail Address

- -<%= render 'form', bounced_mail_address: @bounced_mail_address %> - -<%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/app/views/admin/bounced_mail_addresses/show.html.erb b/app/views/admin/bounced_mail_addresses/show.html.erb index 1f48ad5cf..752bd7b0a 100644 --- a/app/views/admin/bounced_mail_addresses/show.html.erb +++ b/app/views/admin/bounced_mail_addresses/show.html.erb @@ -16,9 +16,13 @@

- Response json: - <%= @bounced_mail_address.response_json %> + Bounced recipient JSON: +

<%= JSON.pretty_generate(@bounced_mail_address.recipient_json) %>
+

+ +

+ Bounce payload: +

<%= JSON.pretty_generate(@bounced_mail_address.response_json) %>

-<%= link_to 'Edit', edit_admin_bounced_mail_address_path(@bounced_mail_address) %> | <%= link_to 'Back', admin_bounced_mail_addresses_path %> diff --git a/config/locales/admin/menu.en.yml b/config/locales/admin/menu.en.yml index 617341c6a..cb1060e6f 100644 --- a/config/locales/admin/menu.en.yml +++ b/config/locales/admin/menu.en.yml @@ -14,6 +14,7 @@ en: blocked_domains: Blocked domains reserved_domains: Reserved domains disputed_domains: Disputed domains + bounced_email_addresses: Bounced emails epp_log: EPP log repp_log: REPP log que: Que diff --git a/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb b/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb new file mode 100644 index 000000000..bad3d846e --- /dev/null +++ b/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb @@ -0,0 +1,5 @@ +class AddRecipientJsonToBouncedMailAddress < ActiveRecord::Migration[6.0] + def change + add_column :bounced_mail_addresses, :recipient_json, :jsonb, null: false + end +end diff --git a/db/structure.sql b/db/structure.sql index 3ec055386..23669c665 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -486,7 +486,8 @@ CREATE TABLE public.bounced_mail_addresses ( incidents integer DEFAULT 1 NOT NULL, response_json jsonb, created_at timestamp(6) without time zone NOT NULL, - updated_at timestamp(6) without time zone NOT NULL + updated_at timestamp(6) without time zone NOT NULL, + recipient_json jsonb NOT NULL ); @@ -4956,6 +4957,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200908131554'), ('20200910085157'), ('20200910102028'), -('20200916125326'); +('20200916125326'), +('20200917104213'); From b2c5a9a5ec69ac8b27e7fa7ab8fef96f292f1485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 15:55:37 +0300 Subject: [PATCH 007/106] Verify param integrity for bounces --- app/controllers/api/v1/bounces_controller.rb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/bounces_controller.rb b/app/controllers/api/v1/bounces_controller.rb index cff8c3efe..40a3c1c91 100644 --- a/app/controllers/api/v1/bounces_controller.rb +++ b/app/controllers/api/v1/bounces_controller.rb @@ -1,11 +1,20 @@ module Api module V1 class BouncesController < BaseController - before_action :authenticate - + # POST api/v1/bounces/ def create - bounced_mail_address = BouncedMailAddress.record(json) - bounced_mail_address ? render(head: :ok) : render(head: :failed) + BouncedMailAddress.record(bounce_params) + head(:ok) + 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 From 03182f92227acceae7c1cf6a08e192e1c44472d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 17 Sep 2020 16:26:50 +0300 Subject: [PATCH 008/106] Implement shared key authentication to bounces API --- app/controllers/api/v1/base_controller.rb | 5 +++++ app/controllers/api/v1/bounces_controller.rb | 4 +++- config/application.yml.sample | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index 54930edf9..b62b3e063 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -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' } diff --git a/app/controllers/api/v1/bounces_controller.rb b/app/controllers/api/v1/bounces_controller.rb index 40a3c1c91..296c9d9bd 100644 --- a/app/controllers/api/v1/bounces_controller.rb +++ b/app/controllers/api/v1/bounces_controller.rb @@ -1,10 +1,12 @@ module Api module V1 class BouncesController < BaseController + before_action :authenticate_shared_key + # POST api/v1/bounces/ def create BouncedMailAddress.record(bounce_params) - head(:ok) + head(:created) rescue ActionController::ParameterMissing head(:bad_request) end diff --git a/config/application.yml.sample b/config/application.yml.sample index 72b55e2ea..237617be3 100644 --- a/config/application.yml.sample +++ b/config/application.yml.sample @@ -87,6 +87,9 @@ sk_digi_doc_service_name: 'Testimine' registrant_api_base_url: registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas +# Bounces API +api_shared_key: testkey + # # MISC From 036a3a37207f4a89d01aad6361e59bd7d7297ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Sep 2020 10:52:14 +0300 Subject: [PATCH 009/106] Return empty user object when authorized user not found --- app/controllers/registrar/sessions_controller.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/controllers/registrar/sessions_controller.rb b/app/controllers/registrar/sessions_controller.rb index 5bebe5619..709e66955 100644 --- a/app/controllers/registrar/sessions_controller.rb +++ b/app/controllers/registrar/sessions_controller.rb @@ -158,12 +158,15 @@ 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) - return selected_user - end + next unless selected_user.registrar.white_ips.registrar_area.include_ip?(request.ip) + + return selected_user end + + User.new end def check_ip_restriction From 7d8c24533af3727b0817db6822b89eb35b373472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Sep 2020 14:44:40 +0300 Subject: [PATCH 010/106] Create unit tests for bounced mail address --- app/models/bounced_mail_address.rb | 11 ++++- test/models/bounced_mail_address_test.rb | 61 ++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 test/models/bounced_mail_address_test.rb diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index 78f37c374..f12c7f19c 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,21 +1,28 @@ class BouncedMailAddress < ApplicationRecord validates :email, presence: true - validates :bounce_reason, presence: true + validates :bounce_reason, :recipient_json, :response_json, presence: true before_validation :assign_bounce_reason def assign_bounce_reason - self.bounce_reason = "#{action} (#{status} #{diagnostic})" + if recipient_json + self.bounce_reason = "#{action} (#{status} #{diagnostic})" + else + self.bounce_reason = nil + end end def diagnostic + return nil unless recipient_json recipient_json['diagnosticCode'] end def action + return nil unless recipient_json recipient_json['action'] end def status + return nil unless recipient_json recipient_json['status'] end diff --git a/test/models/bounced_mail_address_test.rb b/test/models/bounced_mail_address_test.rb new file mode 100644 index 000000000..2caea7d98 --- /dev/null +++ b/test/models/bounced_mail_address_test.rb @@ -0,0 +1,61 @@ +require 'test_helper' + +class BouncedMailAddressTest < ActiveSupport::TestCase + include ActionMailer::TestHelper + + def setup + @bounced_mail = BouncedMailAddress.new + @bounced_mail.email = 'recipient@registry.test' + @bounced_mail.bounce_reason = 'failed (5.1.1 smtp; 550 5.1.1 user unknown)' + @bounced_mail.response_json = {"mail"=>{"source"=>"noreply@internet.test", "sourceIp"=>"195.43.86.5", "messageId"=>"010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", "sourceArn"=>"arn:aws:ses:us-east-2:650268220328:identity/noreply@internet.test", "timestamp"=>"2020-09-18T10:34:44.000Z", "destination"=>["#{@bounced_mail.email}"], "sendingAccountId"=>"650268220328"}, "bounce"=>{"timestamp"=>"2020-09-18T10:34:44.911Z", "bounceType"=>"Permanent", "feedbackId"=>"010f0174a0c7d4f9-27d59756-6111-xxxx-a507-26bee0d55fa2-000000", "remoteMtaIp"=>"127.0.0.1", "reportingMTA"=>"dsn; xxx.amazonses.com", "bounceSubType"=>"General", "bouncedRecipients"=>[{"action"=>"failed", "status"=>"5.1.1", "emailAddress"=>"#{@bounced_mail.email}", "diagnosticCode"=>"smtp; 550 5.1.1 user unknown"}]}, "notificationType"=>"Bounce"} + @bounced_mail.recipient_json = {"action"=>"failed", "status"=>"5.1.1", "emailAddress"=>"#{@bounced_mail.email}", "diagnosticCode"=>"smtp; 550 5.1.1 user unknown"} + + end + + def test_bounce_reason_is_autoassigned + assert @bounced_mail.valid? + @bounced_mail.bounce_reason = nil + assert @bounced_mail.valid? + + assert_equal 'failed (5.1.1 smtp; 550 5.1.1 user unknown)', @bounced_mail.bounce_reason + end + + def test_response_json_is_required + assert @bounced_mail.valid? + @bounced_mail.response_json = nil + assert_not @bounced_mail.valid? + assert @bounced_mail.errors.full_messages.include? 'Response json is missing' + end + + def test_recipient_json_is_required + assert @bounced_mail.valid? + @bounced_mail.recipient_json = nil + assert_not @bounced_mail.valid? + + assert @bounced_mail.errors.full_messages.include? 'Recipient json is missing' + end + + def test_status_is_determined_dynamically + assert @bounced_mail.valid? + assert_equal '5.1.1', @bounced_mail.status + @bounced_mail.recipient_json['status'] = 'xxx_status' + assert_equal 'xxx_status', @bounced_mail.status + end + + def test_action_is_determined_dynamically + assert @bounced_mail.valid? + assert_equal 'failed', @bounced_mail.action + @bounced_mail.recipient_json['action'] = 'xxx_action' + assert_equal 'xxx_action', @bounced_mail.action + end + + def test_diagnostic_is_determined_dynamically + assert @bounced_mail.valid? + assert_equal 'smtp; 550 5.1.1 user unknown', @bounced_mail.diagnostic + @bounced_mail.recipient_json['diagnosticCode'] = 'xxx_diagnostic' + assert_equal 'xxx_diagnostic', @bounced_mail.diagnostic + end + + def test_creates_objects_from_sns_json + end +end From 64308e11040fcc172ce2dd30b25a7179258e58a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Sep 2020 14:49:27 +0300 Subject: [PATCH 011/106] Fix CC issues --- .../registrar/sessions_controller.rb | 8 ++-- app/models/bounced_mail_address.rb | 17 +++++---- test/models/bounced_mail_address_test.rb | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/app/controllers/registrar/sessions_controller.rb b/app/controllers/registrar/sessions_controller.rb index 709e66955..df90ea57b 100644 --- a/app/controllers/registrar/sessions_controller.rb +++ b/app/controllers/registrar/sessions_controller.rb @@ -161,12 +161,10 @@ class Registrar possible_users = ApiUser.where(identity_code: idc) || User.new possible_users.each do |selected_user| - next unless selected_user.registrar.white_ips.registrar_area.include_ip?(request.ip) - - return selected_user + if selected_user.registrar.white_ips.registrar_area.include_ip?(request.ip) + return selected_user + end end - - User.new end def check_ip_restriction diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index f12c7f19c..02bb42337 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -4,25 +4,26 @@ class BouncedMailAddress < ApplicationRecord before_validation :assign_bounce_reason def assign_bounce_reason - if recipient_json - self.bounce_reason = "#{action} (#{status} #{diagnostic})" - else - self.bounce_reason = nil - end + return self.bounce_reason = nil unless recipient_json + + self.bounce_reason = "#{action} (#{status} #{diagnostic})" end def diagnostic - return nil unless recipient_json + return unless recipient_json + recipient_json['diagnosticCode'] end def action - return nil unless recipient_json + return unless recipient_json + recipient_json['action'] end def status - return nil unless recipient_json + return unless recipient_json + recipient_json['status'] end diff --git a/test/models/bounced_mail_address_test.rb b/test/models/bounced_mail_address_test.rb index 2caea7d98..0e6a62ab8 100644 --- a/test/models/bounced_mail_address_test.rb +++ b/test/models/bounced_mail_address_test.rb @@ -57,5 +57,43 @@ class BouncedMailAddressTest < ActiveSupport::TestCase end def test_creates_objects_from_sns_json + BouncedMailAddress.record(sns_bounce_payload) + + bounced_mail = BouncedMailAddress.last + assert_equal domains(:shop).registrant.email, bounced_mail.email + assert_equal 'failed', bounced_mail.action + assert_equal '5.1.1', bounced_mail.status + assert_equal 'smtp; 550 5.1.1 user unknown', bounced_mail.diagnostic + end + + def sns_bounce_payload + { + "notificationType": "Bounce", + "mail": { + "source": "noreply@registry.test", + "sourceIp": "195.43.86.5", + "messageId": "010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", + "sourceArn": "arn:aws:ses:us-east-2:65026820000:identity/noreply@registry.test", + "timestamp": "2020-09-18T10:34:44.000Z", + "destination": [ "#{domains(:shop).registrant.email}" ], + "sendingAccountId": "650268220000" + }, + "bounce": { + "timestamp": "2020-09-18T10:34:44.911Z", + "bounceType": "Permanent", + "feedbackId": "010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000", + "remoteMtaIp": "127.0.01", + "reportingMTA": "dsn; xxx.amazonses.com", + "bounceSubType": "General", + "bouncedRecipients": [ + { + "action": "failed", + "status": "5.1.1", + "emailAddress": "#{domains(:shop).registrant.email}", + "diagnosticCode": "smtp; 550 5.1.1 user unknown" + } + ] + } + }.as_json end end From 101d5d4a7846fea4c3e242dcf3c57af5eb4b5bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Sep 2020 16:17:42 +0300 Subject: [PATCH 012/106] Add tests for admin bounced mails views --- .../bounced_mail_addresses_controller.rb | 10 ----- .../bounced_mail_addresses/index.html.erb | 2 - .../bounced_mail_addresses/show.html.erb | 4 +- test/fixtures/bounced_mail_addresses.yml | 40 ++++++++++++++++++ .../admin_area/bounced_mail_addresses_test.rb | 41 +++++++++++++++++++ 5 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 test/fixtures/bounced_mail_addresses.yml create mode 100644 test/system/admin_area/bounced_mail_addresses_test.rb diff --git a/app/controllers/admin/bounced_mail_addresses_controller.rb b/app/controllers/admin/bounced_mail_addresses_controller.rb index da9421450..1c59acaa4 100644 --- a/app/controllers/admin/bounced_mail_addresses_controller.rb +++ b/app/controllers/admin/bounced_mail_addresses_controller.rb @@ -26,15 +26,5 @@ module Admin def set_bounced_mail_address @bounced_mail_address = BouncedMailAddress.find(params[:id]) end - - # Only allow a trusted parameter "white list" through. - def bounced_mail_address_params - params.require(:bounced_mail_address).permit( - :email, - :bounce_reason, - :incidents, - :response_json - ) - end end end diff --git a/app/views/admin/bounced_mail_addresses/index.html.erb b/app/views/admin/bounced_mail_addresses/index.html.erb index b6a019282..913cbd19d 100644 --- a/app/views/admin/bounced_mail_addresses/index.html.erb +++ b/app/views/admin/bounced_mail_addresses/index.html.erb @@ -1,5 +1,3 @@ -

<%= notice %>

-

Bounced Mail Addresses

diff --git a/app/views/admin/bounced_mail_addresses/show.html.erb b/app/views/admin/bounced_mail_addresses/show.html.erb index 752bd7b0a..9b0b5919f 100644 --- a/app/views/admin/bounced_mail_addresses/show.html.erb +++ b/app/views/admin/bounced_mail_addresses/show.html.erb @@ -1,6 +1,3 @@ -

<%= notice %>

- -

Email: <%= @bounced_mail_address.email %>

@@ -26,3 +23,4 @@

<%= 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?' } %> diff --git a/test/fixtures/bounced_mail_addresses.yml b/test/fixtures/bounced_mail_addresses.yml new file mode 100644 index 000000000..1261f1429 --- /dev/null +++ b/test/fixtures/bounced_mail_addresses.yml @@ -0,0 +1,40 @@ +one: + email: bounced@registry.test + bounce_reason: failed (5.1.1 smtp; 550 5.1.1 user unknown) + incidents: 1 + recipient_json: { + "action": "failed", + "status": "5.1.1", + "emailAddress": "bounced@registry.test", + "diagnosticCode": "smtp; 550 5.1.1 user unknown" + } + response_json: { + "notificationType": "Bounce", + "mail": { + "source": "noreply@registry.test", + "sourceIp": "195.43.86.5", + "messageId": "010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", + "sourceArn": "arn:aws:ses:us-east-2:65026820000:identity/noreply@registry.test", + "timestamp": "2020-09-18T10:34:44.000Z", + "destination": [ "bounced@registry.test" ], + "sendingAccountId": "650268220000" + }, + "bounce": { + "timestamp": "2020-09-18T10:34:44.911Z", + "bounceType": "Permanent", + "feedbackId": "010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000", + "remoteMtaIp": "127.0.01", + "reportingMTA": "dsn; xxx.amazonses.com", + "bounceSubType": "General", + "bouncedRecipients": [ + { + "action": "failed", + "status": "5.1.1", + "emailAddress": "bounced@registry.test", + "diagnosticCode": "smtp; 550 5.1.1 user unknown" + } + ] + } + } + created_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %> + updated_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %> diff --git a/test/system/admin_area/bounced_mail_addresses_test.rb b/test/system/admin_area/bounced_mail_addresses_test.rb new file mode 100644 index 000000000..5500f4375 --- /dev/null +++ b/test/system/admin_area/bounced_mail_addresses_test.rb @@ -0,0 +1,41 @@ +require 'application_system_test_case' + +class AdminBouncedMailAddressesTest < ApplicationSystemTestCase + include ActionView::Helpers::NumberHelper + + def setup + @bounced_mail = bounced_mail_addresses(:one) + @original_default_language = Setting.default_language + sign_in users(:admin) + end + + def teardown + Setting.default_language = @original_default_language + end + + def test_shows_bounced_emails + visit admin_bounced_mail_addresses_path + assert_text @bounced_mail.status + assert_text @bounced_mail.action + assert_text @bounced_mail.diagnostic + assert_text @bounced_mail.email + end + + def test_shows_detailed_bounced_email + visit admin_bounced_mail_address_path(@bounced_mail) + assert_text @bounced_mail.status + assert_text @bounced_mail.action + assert_text @bounced_mail.diagnostic + assert_text @bounced_mail.email + + assert_text 'bouncedRecipients' + assert_text '010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000' + end + + def test_deletes_registrar + visit admin_bounced_mail_address_path(@bounced_mail) + click_on 'Destroy' + + assert_text 'Bounced mail address was successfully destroyed.' + end +end From 6a93395fa493252f5f717799a0f5943257e1ddb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Sep 2020 11:37:31 +0300 Subject: [PATCH 013/106] Add integration tests for Bounces API --- app/controllers/api/v1/bounces_controller.rb | 2 + .../integration/api/v1/bounces/create_test.rb | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 test/integration/api/v1/bounces/create_test.rb diff --git a/app/controllers/api/v1/bounces_controller.rb b/app/controllers/api/v1/bounces_controller.rb index 296c9d9bd..fd10a3398 100644 --- a/app/controllers/api/v1/bounces_controller.rb +++ b/app/controllers/api/v1/bounces_controller.rb @@ -5,6 +5,8 @@ module Api # 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 diff --git a/test/integration/api/v1/bounces/create_test.rb b/test/integration/api/v1/bounces/create_test.rb new file mode 100644 index 000000000..899b6c5c7 --- /dev/null +++ b/test/integration/api/v1/bounces/create_test.rb @@ -0,0 +1,75 @@ +require 'test_helper' + +class BouncesApiV1CreateTest < ActionDispatch::IntegrationTest + def setup + @api_key = "Basic #{ENV['api_shared_key']}" + @headers = { "Authorization": "#{@api_key}" } + @json_body = { "data": valid_bounce_request }.as_json + end + + def test_authorizes_api_request + post api_v1_bounces_path, params: @json_body, headers: @headers + assert_response :created + + invalid_headers = { "Authorization": "Basic invalid_api_key" } + post api_v1_bounces_path, params: @json_body, headers: invalid_headers + assert_response :unauthorized + end + + def test_returns_bad_request_if_invalid_payload + invalid_json_body = @json_body.dup + invalid_json_body['data']['bounce']['bouncedRecipients'] = nil + + post api_v1_bounces_path, params: invalid_json_body, headers: @headers + assert_response :bad_request + + invalid_json_body = 'aaaa' + post api_v1_bounces_path, params: invalid_json_body, headers: @headers + assert_response :bad_request + end + + def test_saves_new_bounce_object + request_body = @json_body.dup + random_mail = "#{rand(10000..99999)}@registry.test" + request_body['data']['bounce']['bouncedRecipients'][0]['emailAddress'] = random_mail + + post api_v1_bounces_path, params: request_body, headers: @headers + assert_response :created + + bounced_mail = BouncedMailAddress.last + assert bounced_mail.email = random_mail + assert '5.1.1', bounced_mail.status + assert 'failed', bounced_mail.action + end + + def valid_bounce_request + { + "notificationType": "Bounce", + "mail": { + "source": "noreply@registry.test", + "sourceIp": "195.43.86.5", + "messageId": "010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", + "sourceArn": "arn:aws:ses:us-east-2:65026820000:identity/noreply@registry.test", + "timestamp": "2020-09-18T10:34:44.000Z", + "destination": [ "bounced@registry.test" ], + "sendingAccountId": "650268220000" + }, + "bounce": { + "timestamp": "2020-09-18T10:34:44.911Z", + "bounceType": "Permanent", + "feedbackId": "010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000", + "remoteMtaIp": "127.0.01", + "reportingMTA": "dsn; xxx.amazonses.com", + "bounceSubType": "General", + "bouncedRecipients": [ + { + "action": "failed", + "status": "5.1.1", + "emailAddress": "bounced@registry.test", + "diagnosticCode": "smtp; 550 5.1.1 user unknown" + } + ] + } + }.as_json + end +end From 818869d249d4e5ebdf1945f454968a0ebcd8c78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Sep 2020 11:46:42 +0300 Subject: [PATCH 014/106] Remove incidents count from bounced mails --- app/views/admin/bounced_mail_addresses/show.html.erb | 5 ----- ...84356_remove_incidents_from_bounced_mail_addresses.rb | 9 +++++++++ db/structure.sql | 4 ++-- test/fixtures/bounced_mail_addresses.yml | 1 - 4 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb diff --git a/app/views/admin/bounced_mail_addresses/show.html.erb b/app/views/admin/bounced_mail_addresses/show.html.erb index 9b0b5919f..98eeabcd2 100644 --- a/app/views/admin/bounced_mail_addresses/show.html.erb +++ b/app/views/admin/bounced_mail_addresses/show.html.erb @@ -7,11 +7,6 @@ <%= @bounced_mail_address.bounce_reason %>

-

- Incidents: - <%= @bounced_mail_address.incidents %> -

-

Bounced recipient JSON:

<%= JSON.pretty_generate(@bounced_mail_address.recipient_json) %>
diff --git a/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb b/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb new file mode 100644 index 000000000..0704795df --- /dev/null +++ b/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb @@ -0,0 +1,9 @@ +class RemoveIncidentsFromBouncedMailAddresses < ActiveRecord::Migration[6.0] + def up + remove_column :bounced_mail_addresses, :incidents + end + + def down + add_column :bounced_mail_addresses, :incidents, :integer, null: false, default: 1 + end +end diff --git a/db/structure.sql b/db/structure.sql index 23669c665..74e784408 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -483,7 +483,6 @@ CREATE TABLE public.bounced_mail_addresses ( id bigint NOT NULL, email character varying NOT NULL, bounce_reason character varying NOT NULL, - incidents integer DEFAULT 1 NOT NULL, response_json jsonb, created_at timestamp(6) without time zone NOT NULL, updated_at timestamp(6) without time zone NOT NULL, @@ -4958,6 +4957,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200910085157'), ('20200910102028'), ('20200916125326'), -('20200917104213'); +('20200917104213'), +('20200921084356'); diff --git a/test/fixtures/bounced_mail_addresses.yml b/test/fixtures/bounced_mail_addresses.yml index 1261f1429..345b2ef22 100644 --- a/test/fixtures/bounced_mail_addresses.yml +++ b/test/fixtures/bounced_mail_addresses.yml @@ -1,7 +1,6 @@ one: email: bounced@registry.test bounce_reason: failed (5.1.1 smtp; 550 5.1.1 user unknown) - incidents: 1 recipient_json: { "action": "failed", "status": "5.1.1", From fae620c19d87fc4df9710be88e3608a4192b29a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Sep 2020 13:12:23 +0300 Subject: [PATCH 015/106] Define routing scope for :bounced_mail_addresses --- config/routes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 89f8f0cd6..9938403e7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -299,7 +299,7 @@ Rails.application.routes.draw do resources :delayed_jobs resources :epp_logs resources :repp_logs - resources :bounced_mail_addresses + resources :bounced_mail_addresses, only: %i[index show destroy] authenticate :admin_user do mount Que::Web, at: 'que' From 659cb7f4e67ee51545b6ea0ce5b20e030e881591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Sep 2020 13:34:34 +0300 Subject: [PATCH 016/106] Combine migrations, remove json objects from bounced mails --- ...0200916125326_create_bounced_mail_addresses.rb | 9 ++++++--- ..._add_recipient_json_to_bounced_mail_address.rb | 5 ----- ...emove_incidents_from_bounced_mail_addresses.rb | 9 --------- db/structure.sql | 15 ++++++++------- 4 files changed, 14 insertions(+), 24 deletions(-) delete mode 100644 db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb delete mode 100644 db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb diff --git a/db/migrate/20200916125326_create_bounced_mail_addresses.rb b/db/migrate/20200916125326_create_bounced_mail_addresses.rb index c6600afea..e1744cc9a 100644 --- a/db/migrate/20200916125326_create_bounced_mail_addresses.rb +++ b/db/migrate/20200916125326_create_bounced_mail_addresses.rb @@ -2,9 +2,12 @@ class CreateBouncedMailAddresses < ActiveRecord::Migration[6.0] def change create_table :bounced_mail_addresses do |t| t.string :email, null: false - t.string :bounce_reason, null: false - t.integer :incidents, null: false, default: 1 - t.jsonb :response_json + t.string :message_id, null: false + t.string :bounce_type, null: false + t.string :bounce_subtype, null: false + t.string :action, null: false + t.string :status, null: false + t.string :diagnostic, null: true t.timestamps end diff --git a/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb b/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb deleted file mode 100644 index bad3d846e..000000000 --- a/db/migrate/20200917104213_add_recipient_json_to_bounced_mail_address.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddRecipientJsonToBouncedMailAddress < ActiveRecord::Migration[6.0] - def change - add_column :bounced_mail_addresses, :recipient_json, :jsonb, null: false - end -end diff --git a/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb b/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb deleted file mode 100644 index 0704795df..000000000 --- a/db/migrate/20200921084356_remove_incidents_from_bounced_mail_addresses.rb +++ /dev/null @@ -1,9 +0,0 @@ -class RemoveIncidentsFromBouncedMailAddresses < ActiveRecord::Migration[6.0] - def up - remove_column :bounced_mail_addresses, :incidents - end - - def down - add_column :bounced_mail_addresses, :incidents, :integer, null: false, default: 1 - end -end diff --git a/db/structure.sql b/db/structure.sql index 74e784408..e064d968f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -482,11 +482,14 @@ ALTER SEQUENCE public.blocked_domains_id_seq OWNED BY public.blocked_domains.id; CREATE TABLE public.bounced_mail_addresses ( id bigint NOT NULL, email character varying NOT NULL, - bounce_reason character varying NOT NULL, - response_json jsonb, + message_id character varying NOT NULL, + bounce_type character varying NOT NULL, + bounce_subtype character varying NOT NULL, + action character varying NOT NULL, + status character varying NOT NULL, + diagnostic character varying, created_at timestamp(6) without time zone NOT NULL, - updated_at timestamp(6) without time zone NOT NULL, - recipient_json jsonb NOT NULL + updated_at timestamp(6) without time zone NOT NULL ); @@ -4956,8 +4959,6 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200908131554'), ('20200910085157'), ('20200910102028'), -('20200916125326'), -('20200917104213'), -('20200921084356'); +('20200916125326'); From 98674ab3817148e6c5e15acd7b48a956e3ef58d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Sep 2020 13:47:57 +0300 Subject: [PATCH 017/106] Reflect new bounced mail structure --- app/models/bounced_mail_address.rb | 36 ++++++++----------- .../bounced_mail_addresses/show.html.erb | 18 ++++++---- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index 02bb42337..61679f543 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,6 +1,5 @@ class BouncedMailAddress < ApplicationRecord - validates :email, presence: true - validates :bounce_reason, :recipient_json, :response_json, presence: true + validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true before_validation :assign_bounce_reason def assign_bounce_reason @@ -9,31 +8,24 @@ class BouncedMailAddress < ApplicationRecord self.bounce_reason = "#{action} (#{status} #{diagnostic})" end - def diagnostic - return unless recipient_json - - recipient_json['diagnosticCode'] - end - - def action - return unless recipient_json - - recipient_json['action'] - end - - def status - return unless recipient_json - - recipient_json['status'] - end - def self.record(json) bounced_records = json['bounce']['bouncedRecipients'] bounced_records.each do |record| - bounce_record = BouncedMailAddress.new(email: record['emailAddress'], recipient_json: record, - response_json: json) + bounce_record = BouncedMailAddress.new(params_from_json(json, record)) bounce_record.save end end + + def 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 diff --git a/app/views/admin/bounced_mail_addresses/show.html.erb b/app/views/admin/bounced_mail_addresses/show.html.erb index 98eeabcd2..5183ae5a1 100644 --- a/app/views/admin/bounced_mail_addresses/show.html.erb +++ b/app/views/admin/bounced_mail_addresses/show.html.erb @@ -1,20 +1,26 @@ +

Email: <%= @bounced_mail_address.email %>

- Bounce reason: - <%= @bounced_mail_address.bounce_reason %> + Bounced message ID: + <%= @bounced_mail_address.message_id %>

- Bounced recipient JSON: -

<%= JSON.pretty_generate(@bounced_mail_address.recipient_json) %>
+ Overall bounce type: + <%= @bounced_mail_address.bounce_type %> (<%= @bounced_mail_address.bounce_subtype %> )

- Bounce payload: -

<%= JSON.pretty_generate(@bounced_mail_address.response_json) %>
+ Bounced recipient status: + <%= @bounced_mail_address.action %> (<%= @bounced_mail_address.status %>) +

+ +

+ Bounced recipient diagnostic: +

<%= @bounced_mail_address.diagnostic %>

<%= link_to 'Back', admin_bounced_mail_addresses_path %> From 3222a8b9a79b80444a41b8b348c98d8d260aeb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 30 Sep 2020 12:48:21 +0300 Subject: [PATCH 018/106] Bounces: Fix tests --- app/models/bounced_mail_address.rb | 9 +- test/fixtures/bounced_mail_addresses.yml | 41 ++------- test/models/bounced_mail_address_test.rb | 91 ++++++++++--------- .../admin_area/bounced_mail_addresses_test.rb | 3 +- 4 files changed, 58 insertions(+), 86 deletions(-) diff --git a/app/models/bounced_mail_address.rb b/app/models/bounced_mail_address.rb index 61679f543..73c6a0941 100644 --- a/app/models/bounced_mail_address.rb +++ b/app/models/bounced_mail_address.rb @@ -1,11 +1,8 @@ class BouncedMailAddress < ApplicationRecord validates :email, :message_id, :bounce_type, :bounce_subtype, :action, :status, presence: true - before_validation :assign_bounce_reason - def assign_bounce_reason - return self.bounce_reason = nil unless recipient_json - - self.bounce_reason = "#{action} (#{status} #{diagnostic})" + def bounce_reason + "#{action} (#{status} #{diagnostic})" end def self.record(json) @@ -17,7 +14,7 @@ class BouncedMailAddress < ApplicationRecord end end - def params_from_json(json, bounced_record) + def self.params_from_json(json, bounced_record) { email: bounced_record['emailAddress'], message_id: json['mail']['messageId'], diff --git a/test/fixtures/bounced_mail_addresses.yml b/test/fixtures/bounced_mail_addresses.yml index 345b2ef22..cbfdff680 100644 --- a/test/fixtures/bounced_mail_addresses.yml +++ b/test/fixtures/bounced_mail_addresses.yml @@ -1,39 +1,10 @@ one: email: bounced@registry.test - bounce_reason: failed (5.1.1 smtp; 550 5.1.1 user unknown) - recipient_json: { - "action": "failed", - "status": "5.1.1", - "emailAddress": "bounced@registry.test", - "diagnosticCode": "smtp; 550 5.1.1 user unknown" - } - response_json: { - "notificationType": "Bounce", - "mail": { - "source": "noreply@registry.test", - "sourceIp": "195.43.86.5", - "messageId": "010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", - "sourceArn": "arn:aws:ses:us-east-2:65026820000:identity/noreply@registry.test", - "timestamp": "2020-09-18T10:34:44.000Z", - "destination": [ "bounced@registry.test" ], - "sendingAccountId": "650268220000" - }, - "bounce": { - "timestamp": "2020-09-18T10:34:44.911Z", - "bounceType": "Permanent", - "feedbackId": "010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000", - "remoteMtaIp": "127.0.01", - "reportingMTA": "dsn; xxx.amazonses.com", - "bounceSubType": "General", - "bouncedRecipients": [ - { - "action": "failed", - "status": "5.1.1", - "emailAddress": "bounced@registry.test", - "diagnosticCode": "smtp; 550 5.1.1 user unknown" - } - ] - } - } + message_id: 010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000 + bounce_type: Permanent + bounce_subtype: General + action: failed + status: '5.1.1' + diagnostic: 'smtp; 550 5.1.1 user unknown' created_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %> updated_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %> diff --git a/test/models/bounced_mail_address_test.rb b/test/models/bounced_mail_address_test.rb index 0e6a62ab8..4af401711 100644 --- a/test/models/bounced_mail_address_test.rb +++ b/test/models/bounced_mail_address_test.rb @@ -6,56 +6,61 @@ class BouncedMailAddressTest < ActiveSupport::TestCase def setup @bounced_mail = BouncedMailAddress.new @bounced_mail.email = 'recipient@registry.test' - @bounced_mail.bounce_reason = 'failed (5.1.1 smtp; 550 5.1.1 user unknown)' - @bounced_mail.response_json = {"mail"=>{"source"=>"noreply@internet.test", "sourceIp"=>"195.43.86.5", "messageId"=>"010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000", "sourceArn"=>"arn:aws:ses:us-east-2:650268220328:identity/noreply@internet.test", "timestamp"=>"2020-09-18T10:34:44.000Z", "destination"=>["#{@bounced_mail.email}"], "sendingAccountId"=>"650268220328"}, "bounce"=>{"timestamp"=>"2020-09-18T10:34:44.911Z", "bounceType"=>"Permanent", "feedbackId"=>"010f0174a0c7d4f9-27d59756-6111-xxxx-a507-26bee0d55fa2-000000", "remoteMtaIp"=>"127.0.0.1", "reportingMTA"=>"dsn; xxx.amazonses.com", "bounceSubType"=>"General", "bouncedRecipients"=>[{"action"=>"failed", "status"=>"5.1.1", "emailAddress"=>"#{@bounced_mail.email}", "diagnosticCode"=>"smtp; 550 5.1.1 user unknown"}]}, "notificationType"=>"Bounce"} - @bounced_mail.recipient_json = {"action"=>"failed", "status"=>"5.1.1", "emailAddress"=>"#{@bounced_mail.email}", "diagnosticCode"=>"smtp; 550 5.1.1 user unknown"} - + @bounced_mail.message_id = '010f0174a0c7d348-ea6e2fc1-0854-4073-b71f-5cecf9b0d0b2-000000' + @bounced_mail.bounce_type = 'Permanent' + @bounced_mail.bounce_subtype = 'General' + @bounced_mail.action = 'failed' + @bounced_mail.status = '5.1.1' + @bounced_mail.diagnostic = 'smtp; 550 5.1.1 user unknown' end - def test_bounce_reason_is_autoassigned - assert @bounced_mail.valid? - @bounced_mail.bounce_reason = nil + def test_email_is_required assert @bounced_mail.valid? + @bounced_mail.email = nil + assert @bounced_mail.invalid? + end + def test_message_id_is_required + assert @bounced_mail.valid? + @bounced_mail.message_id = nil + assert @bounced_mail.invalid? + end + + def test_bounce_type_is_required + assert @bounced_mail.valid? + @bounced_mail.bounce_type = nil + assert @bounced_mail.invalid? + end + + def test_bounce_subtype_is_required + assert @bounced_mail.valid? + @bounced_mail.bounce_subtype = nil + assert @bounced_mail.invalid? + end + + def test_action_is_required + assert @bounced_mail.valid? + @bounced_mail.action = nil + assert @bounced_mail.invalid? + end + + def test_status_is_required + assert @bounced_mail.valid? + @bounced_mail.status = nil + assert @bounced_mail.invalid? + end + + def test_diagnostic_is_not_required + assert @bounced_mail.valid? + @bounced_mail.diagnostic = nil + assert @bounced_mail.valid? + end + + def test_bounce_reason_is_determined_dynamically + assert @bounced_mail.valid? assert_equal 'failed (5.1.1 smtp; 550 5.1.1 user unknown)', @bounced_mail.bounce_reason end - def test_response_json_is_required - assert @bounced_mail.valid? - @bounced_mail.response_json = nil - assert_not @bounced_mail.valid? - assert @bounced_mail.errors.full_messages.include? 'Response json is missing' - end - - def test_recipient_json_is_required - assert @bounced_mail.valid? - @bounced_mail.recipient_json = nil - assert_not @bounced_mail.valid? - - assert @bounced_mail.errors.full_messages.include? 'Recipient json is missing' - end - - def test_status_is_determined_dynamically - assert @bounced_mail.valid? - assert_equal '5.1.1', @bounced_mail.status - @bounced_mail.recipient_json['status'] = 'xxx_status' - assert_equal 'xxx_status', @bounced_mail.status - end - - def test_action_is_determined_dynamically - assert @bounced_mail.valid? - assert_equal 'failed', @bounced_mail.action - @bounced_mail.recipient_json['action'] = 'xxx_action' - assert_equal 'xxx_action', @bounced_mail.action - end - - def test_diagnostic_is_determined_dynamically - assert @bounced_mail.valid? - assert_equal 'smtp; 550 5.1.1 user unknown', @bounced_mail.diagnostic - @bounced_mail.recipient_json['diagnosticCode'] = 'xxx_diagnostic' - assert_equal 'xxx_diagnostic', @bounced_mail.diagnostic - end - def test_creates_objects_from_sns_json BouncedMailAddress.record(sns_bounce_payload) diff --git a/test/system/admin_area/bounced_mail_addresses_test.rb b/test/system/admin_area/bounced_mail_addresses_test.rb index 5500f4375..36b81f0f8 100644 --- a/test/system/admin_area/bounced_mail_addresses_test.rb +++ b/test/system/admin_area/bounced_mail_addresses_test.rb @@ -28,8 +28,7 @@ class AdminBouncedMailAddressesTest < ApplicationSystemTestCase assert_text @bounced_mail.diagnostic assert_text @bounced_mail.email - assert_text 'bouncedRecipients' - assert_text '010f0174a0c7d4f9-27d59756-6111-4d5f-xxxx-26bee0d55fa2-000000' + assert_text @bounced_mail.message_id end def test_deletes_registrar From 574846c626e23b2368c30c3088de9046f36e946b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 2 Oct 2020 16:02:44 +0300 Subject: [PATCH 019/106] Remove unneeded modifications in structure.sql --- db/structure.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index e064d968f..acf134a55 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1743,7 +1743,7 @@ ALTER SEQUENCE public.log_payment_orders_id_seq OWNED BY public.log_payment_orde -- --- Name: log_prices; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_prices; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.log_prices ( @@ -1781,7 +1781,7 @@ ALTER SEQUENCE public.log_prices_id_seq OWNED BY public.log_prices.id; -- --- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.log_registrant_verifications ( @@ -3401,7 +3401,7 @@ ALTER TABLE ONLY public.log_payment_orders -- --- Name: log_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.log_prices @@ -3409,7 +3409,7 @@ ALTER TABLE ONLY public.log_prices -- --- Name: log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public.log_registrant_verifications From ef5c4bd54ebcdcab6f6544cf5b490494126c4110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 19 Nov 2020 16:15:23 +0200 Subject: [PATCH 020/106] Return total domain count in domains query --- app/controllers/api/v1/registrant/domains_controller.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/registrant/domains_controller.rb b/app/controllers/api/v1/registrant/domains_controller.rb index b985ef390..48cb95cf2 100644 --- a/app/controllers/api/v1/registrant/domains_controller.rb +++ b/app/controllers/api/v1/registrant/domains_controller.rb @@ -18,14 +18,13 @@ module Api status: :bad_request) && return end - @domains = current_user_domains.limit(limit).offset(offset) - - serialized_domains = @domains.map do |item| + domains = current_user_domains + serialized_domains = domains.limit(limit).offset(offset).map do |item| serializer = Serializers::RegistrantApi::Domain.new(item) serializer.to_json end - render json: serialized_domains + render json: {count: domains.count, domains: serialized_domains} end def show From 556008debee12987dfc31edabc4be62a4566cb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 19 Nov 2020 16:18:25 +0200 Subject: [PATCH 021/106] Fix CC issues --- app/controllers/api/v1/registrant/domains_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/registrant/domains_controller.rb b/app/controllers/api/v1/registrant/domains_controller.rb index 48cb95cf2..26f9f813b 100644 --- a/app/controllers/api/v1/registrant/domains_controller.rb +++ b/app/controllers/api/v1/registrant/domains_controller.rb @@ -24,7 +24,7 @@ module Api serializer.to_json end - render json: {count: domains.count, domains: serialized_domains} + render json: { count: domains.count, domains: serialized_domains } end def show From a40116e05e5e80378ef99f861ec824c020ffd276 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 20 Nov 2020 16:51:05 +0500 Subject: [PATCH 022/106] Move ClientHold procedure to interactor Closes #1751 --- .../client_hold_interaction/base.rb | 8 +++ .../process_client_hold.rb | 67 +++++++++++++++++++ .../set_client_hold.rb | 15 +++++ app/models/concerns/domain/force_delete.rb | 19 ------ app/models/concerns/job/force_delete.rb | 34 ---------- .../concerns/job/force_delete_logging.rb | 34 ---------- .../concerns/job/force_delete_notify.rb | 31 --------- app/models/domain_cron.rb | 8 +-- test/models/domain/force_delete_test.rb | 13 ++-- 9 files changed, 102 insertions(+), 127 deletions(-) create mode 100644 app/interactions/client_hold_interaction/base.rb create mode 100644 app/interactions/client_hold_interaction/process_client_hold.rb create mode 100644 app/interactions/client_hold_interaction/set_client_hold.rb delete mode 100644 app/models/concerns/job/force_delete.rb delete mode 100644 app/models/concerns/job/force_delete_logging.rb delete mode 100644 app/models/concerns/job/force_delete_notify.rb diff --git a/app/interactions/client_hold_interaction/base.rb b/app/interactions/client_hold_interaction/base.rb new file mode 100644 index 000000000..be8b8b0a8 --- /dev/null +++ b/app/interactions/client_hold_interaction/base.rb @@ -0,0 +1,8 @@ +module ClientHoldInteraction + class Base < ActiveInteraction::Base + def to_stdout(message) + time = Time.zone.now.utc + STDOUT << "#{time} - #{message}\n" unless Rails.env.test? + end + end +end diff --git a/app/interactions/client_hold_interaction/process_client_hold.rb b/app/interactions/client_hold_interaction/process_client_hold.rb new file mode 100644 index 000000000..453c400cc --- /dev/null +++ b/app/interactions/client_hold_interaction/process_client_hold.rb @@ -0,0 +1,67 @@ +module ClientHoldInteraction + 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 diff --git a/app/interactions/client_hold_interaction/set_client_hold.rb b/app/interactions/client_hold_interaction/set_client_hold.rb new file mode 100644 index 000000000..d723d5cc8 --- /dev/null +++ b/app/interactions/client_hold_interaction/set_client_hold.rb @@ -0,0 +1,15 @@ +module ClientHoldInteraction + 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| + ClientHoldInteraction::ProcessClientHold.run(domain: domain) + end + + to_stdout('All client_hold setting are done\n') + end + end +end diff --git a/app/models/concerns/domain/force_delete.rb b/app/models/concerns/domain/force_delete.rb index ff869fc0a..988c8075a 100644 --- a/app/models/concerns/domain/force_delete.rb +++ b/app/models/concerns/domain/force_delete.rb @@ -33,25 +33,6 @@ 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, diff --git a/app/models/concerns/job/force_delete.rb b/app/models/concerns/job/force_delete.rb deleted file mode 100644 index 316612d1e..000000000 --- a/app/models/concerns/job/force_delete.rb +++ /dev/null @@ -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 diff --git a/app/models/concerns/job/force_delete_logging.rb b/app/models/concerns/job/force_delete_logging.rb deleted file mode 100644 index 8f6ee227c..000000000 --- a/app/models/concerns/job/force_delete_logging.rb +++ /dev/null @@ -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 diff --git a/app/models/concerns/job/force_delete_notify.rb b/app/models/concerns/job/force_delete_notify.rb deleted file mode 100644 index bc291354e..000000000 --- a/app/models/concerns/job/force_delete_notify.rb +++ /dev/null @@ -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 diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index ad64456ca..613762062 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -1,8 +1,4 @@ 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? @@ -81,4 +77,8 @@ class DomainCron STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{marked} of #{real} domains\n" unless Rails.env.test? marked end + + def self.start_client_hold + ClientHoldInteraction::SetClientHold.run! + end end diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index 7c205fa74..d9e7a3632 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -206,9 +206,10 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-08-21') - DomainCron.start_client_hold + ClientHoldInteraction::SetClientHold.run! @domain.reload + assert_emails 1 assert_equal(@domain.purge_date.to_date, @domain.force_delete_date.to_date) assert_equal(@domain.outzone_date.to_date, @domain.force_delete_start.to_date + Setting.expire_warning_period.days) @@ -226,8 +227,10 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-08-21') - DomainCron.start_client_hold + ClientHoldInteraction::SetClientHold.run! @domain.reload + + assert_emails 1 assert_includes(@domain.statuses, asserted_status) end @@ -241,7 +244,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-07-06') - DomainCron.start_client_hold + ClientHoldInteraction::SetClientHold.run! @domain.reload assert_not_includes(@domain.statuses, asserted_status) @@ -256,7 +259,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :fast_track) travel_to Time.zone.parse('2010-07-25') - DomainCron.start_client_hold + ClientHoldInteraction::SetClientHold.run! @domain.reload assert_includes(@domain.statuses, asserted_status) @@ -272,7 +275,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :fast_track) travel_to Time.zone.parse('2010-07-06') - DomainCron.start_client_hold + ClientHoldInteraction::SetClientHold.run! @domain.reload assert_not_includes(@domain.statuses, asserted_status) From a3e6bc4cf90c319a797a3b19cf6188d8360628ff Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 23 Nov 2020 16:31:26 +0500 Subject: [PATCH 023/106] Mode DomainDeleteConfirm job to interactor --- .../send_request.rb | 22 +++++++++++++++++++ app/jobs/domain_delete_confirm_email_job.rb | 18 +-------------- 2 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 app/interactions/domain_delete_confirm_interaction/send_request.rb diff --git a/app/interactions/domain_delete_confirm_interaction/send_request.rb b/app/interactions/domain_delete_confirm_interaction/send_request.rb new file mode 100644 index 000000000..6e734d40d --- /dev/null +++ b/app/interactions/domain_delete_confirm_interaction/send_request.rb @@ -0,0 +1,22 @@ +module DomainDeleteConfirmInteraction + 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_now + 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 diff --git a/app/jobs/domain_delete_confirm_email_job.rb b/app/jobs/domain_delete_confirm_email_job.rb index ea5a9bf49..ef9a1ba96 100644 --- a/app/jobs/domain_delete_confirm_email_job.rb +++ b/app/jobs/domain_delete_confirm_email_job.rb @@ -1,22 +1,6 @@ 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 + DomainDeleteConfirmInteraction::SendRequest.run(domain: domain) end end From cb3cf37331a090d6ab03ef82afdf3bfa228e4568 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 23 Nov 2020 16:57:28 +0500 Subject: [PATCH 024/106] Change email sending from job to delayed send --- .../send_request.rb | 2 +- app/jobs/domain_delete_confirm_email_job.rb | 8 ++++---- app/models/domain.rb | 2 +- test/integration/epp/domain/delete/base_test.rb | 13 +++++++++---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/interactions/domain_delete_confirm_interaction/send_request.rb b/app/interactions/domain_delete_confirm_interaction/send_request.rb index 6e734d40d..bbf4c8d9e 100644 --- a/app/interactions/domain_delete_confirm_interaction/send_request.rb +++ b/app/interactions/domain_delete_confirm_interaction/send_request.rb @@ -8,7 +8,7 @@ module DomainDeleteConfirmInteraction log DomainDeleteMailer.confirmation_request(domain: domain, registrar: domain.registrar, - registrant: domain.registrant).deliver_now + registrant: domain.registrant).deliver_later end private diff --git a/app/jobs/domain_delete_confirm_email_job.rb b/app/jobs/domain_delete_confirm_email_job.rb index ef9a1ba96..d2c814bd8 100644 --- a/app/jobs/domain_delete_confirm_email_job.rb +++ b/app/jobs/domain_delete_confirm_email_job.rb @@ -1,6 +1,6 @@ class DomainDeleteConfirmEmailJob < Que::Job - def run(domain_id) - domain = Domain.find(domain_id) - DomainDeleteConfirmInteraction::SendRequest.run(domain: domain) - end + # def run(domain_id) + # domain = Domain.find(domain_id) + # DomainDeleteConfirmInteraction::SendRequest.run(domain: domain) + # end end diff --git a/app/models/domain.rb b/app/models/domain.rb index b15bb7c55..1ef66ffab 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -418,7 +418,7 @@ class Domain < ApplicationRecord pending_delete_confirmation! save(validate: false) # should check if this did succeed - DomainDeleteConfirmEmailJob.enqueue(id) + DomainDeleteConfirmInteraction::SendRequest.run(domain: self) end def cancel_pending_delete diff --git a/test/integration/epp/domain/delete/base_test.rb b/test/integration/epp/domain/delete/base_test.rb index bfdfa9f75..56a3cc31e 100644 --- a/test/integration/epp/domain/delete/base_test.rb +++ b/test/integration/epp/domain/delete/base_test.rb @@ -35,7 +35,6 @@ class EppDomainDeleteBaseTest < EppTestCase XML post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } - # binding.pry assert_includes Domain.find_by(name: 'invalid.test').statuses, DomainStatus::PENDING_DELETE_CONFIRMATION assert_epp_response :completed_successfully_action_pending end @@ -90,7 +89,9 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + perform_enqueued_jobs do + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end @domain.reload assert @domain.registrant_verification_asked? @@ -121,7 +122,9 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + perform_enqueued_jobs do + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end @domain.reload assert_not @domain.registrant_verification_asked? @@ -152,7 +155,9 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + perform_enqueued_jobs do + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end @domain.reload assert_not @domain.registrant_verification_asked? From 89c5413fc702c8399474ff18f6f245af531deeba Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 24 Nov 2020 13:26:38 +0500 Subject: [PATCH 025/106] Unused class clean-up --- app/jobs/domain_delete_confirm_email_job.rb | 6 ------ test/models/whois/record_test.rb | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 app/jobs/domain_delete_confirm_email_job.rb diff --git a/app/jobs/domain_delete_confirm_email_job.rb b/app/jobs/domain_delete_confirm_email_job.rb deleted file mode 100644 index d2c814bd8..000000000 --- a/app/jobs/domain_delete_confirm_email_job.rb +++ /dev/null @@ -1,6 +0,0 @@ -class DomainDeleteConfirmEmailJob < Que::Job - # def run(domain_id) - # domain = Domain.find(domain_id) - # DomainDeleteConfirmInteraction::SendRequest.run(domain: domain) - # end -end diff --git a/test/models/whois/record_test.rb b/test/models/whois/record_test.rb index e900a4965..d06b23cae 100644 --- a/test/models/whois/record_test.rb +++ b/test/models/whois/record_test.rb @@ -70,6 +70,6 @@ class Whois::RecordTest < ActiveSupport::TestCase end def registration_deadline - Time.zone.now + 10.days + @registration_deadline ||= Time.zone.now + 10.days end end From 09a58fa432193dee065ebcbc0556cc96e877e0d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Fri, 27 Nov 2020 18:12:49 +0200 Subject: [PATCH 026/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebbc3d905..44329c4d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From 7b3361394168656ce305cbbc0e885555fa5e712f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 10:31:46 +0200 Subject: [PATCH 027/106] Reduce domains list API call --- .../api/v1/registrant/domains_controller.rb | 4 ++-- lib/serializers/registrant_api/domain.rb | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/registrant/domains_controller.rb b/app/controllers/api/v1/registrant/domains_controller.rb index 26f9f813b..390148488 100644 --- a/app/controllers/api/v1/registrant/domains_controller.rb +++ b/app/controllers/api/v1/registrant/domains_controller.rb @@ -20,7 +20,7 @@ module Api domains = current_user_domains serialized_domains = domains.limit(limit).offset(offset).map do |item| - serializer = Serializers::RegistrantApi::Domain.new(item) + serializer = Serializers::RegistrantApi::Domain.new(item, simplify: true) serializer.to_json end @@ -31,7 +31,7 @@ module Api @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 diff --git a/lib/serializers/registrant_api/domain.rb b/lib/serializers/registrant_api/domain.rb index 542f2d0de..f0c9c1876 100644 --- a/lib/serializers/registrant_api/domain.rb +++ b/lib/serializers/registrant_api/domain.rb @@ -3,11 +3,27 @@ module Serializers class Domain attr_reader :domain - def initialize(domain) + def initialize(domain, simplify: false) @domain = domain + @simplify = simplify end def to_json + if simplify + return { + id: domain.uuid, + name: domain.name, + registered_at: domain.registered_at, + valid_to: domain.valid_to, + registrant_verification_asked_at: domain.registrant_verification_asked_at, + statuses: domain.statuses, + registrar: { + name: domain.registrar.name, + website: domain.registrar.website + } + } + end + { id: domain.uuid, name: domain.name, From 5363c546a598ecfe8460a43c6bb2c105ea764ab0 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 30 Nov 2020 13:46:53 +0500 Subject: [PATCH 028/106] Move all the existing interactors to Domains namespace --- .../cancel_force_delete_interaction/base.rb | 7 ---- .../cancel_force_delete.rb | 10 ----- .../clear_force_delete_data.rb | 10 ----- .../notify_registrar.rb | 8 ---- .../remove_force_delete_statuses.rb | 11 ----- .../restore_statuses_before_force_delete.rb | 9 ----- .../send_request.rb | 22 ---------- .../domains/cancel_force_delete/base.rb | 9 +++++ .../cancel_force_delete.rb | 12 ++++++ .../clear_force_delete_data.rb | 12 ++++++ .../cancel_force_delete/notify_registrar.rb | 10 +++++ .../remove_force_delete_statuses.rb | 13 ++++++ .../restore_statuses_before_force_delete.rb | 11 +++++ .../domains/delete_confirm/send_request.rb | 24 +++++++++++ app/interactions/domains/force_delete/base.rb | 17 ++++++++ .../domains/force_delete/check_discarded.rb | 12 ++++++ .../domains/force_delete/notify_by_email.rb | 23 +++++++++++ .../domains/force_delete/notify_registrar.rb | 12 ++++++ .../domains/force_delete/post_set_process.rb | 19 +++++++++ .../domains/force_delete/prepare_domain.rb | 15 +++++++ .../domains/force_delete/set_force_delete.rb | 14 +++++++ .../domains/force_delete/set_status.rb | 40 +++++++++++++++++++ .../force_delete_interaction/base.rb | 16 -------- .../check_discarded.rb | 11 ----- .../notify_by_email.rb | 21 ---------- .../notify_registrar.rb | 10 ----- .../post_set_process.rb | 17 -------- .../prepare_domain.rb | 13 ------ .../set_force_delete.rb | 12 ------ .../force_delete_interaction/set_status.rb | 38 ------------------ app/models/concerns/domain/force_delete.rb | 8 ++-- app/models/domain.rb | 2 +- test/models/domain/force_delete_test.rb | 2 +- test/models/domain_test.rb | 2 +- 34 files changed, 250 insertions(+), 222 deletions(-) delete mode 100644 app/interactions/cancel_force_delete_interaction/base.rb delete mode 100644 app/interactions/cancel_force_delete_interaction/cancel_force_delete.rb delete mode 100644 app/interactions/cancel_force_delete_interaction/clear_force_delete_data.rb delete mode 100644 app/interactions/cancel_force_delete_interaction/notify_registrar.rb delete mode 100644 app/interactions/cancel_force_delete_interaction/remove_force_delete_statuses.rb delete mode 100644 app/interactions/cancel_force_delete_interaction/restore_statuses_before_force_delete.rb delete mode 100644 app/interactions/domain_delete_confirm_interaction/send_request.rb create mode 100644 app/interactions/domains/cancel_force_delete/base.rb create mode 100644 app/interactions/domains/cancel_force_delete/cancel_force_delete.rb create mode 100644 app/interactions/domains/cancel_force_delete/clear_force_delete_data.rb create mode 100644 app/interactions/domains/cancel_force_delete/notify_registrar.rb create mode 100644 app/interactions/domains/cancel_force_delete/remove_force_delete_statuses.rb create mode 100644 app/interactions/domains/cancel_force_delete/restore_statuses_before_force_delete.rb create mode 100644 app/interactions/domains/delete_confirm/send_request.rb create mode 100644 app/interactions/domains/force_delete/base.rb create mode 100644 app/interactions/domains/force_delete/check_discarded.rb create mode 100644 app/interactions/domains/force_delete/notify_by_email.rb create mode 100644 app/interactions/domains/force_delete/notify_registrar.rb create mode 100644 app/interactions/domains/force_delete/post_set_process.rb create mode 100644 app/interactions/domains/force_delete/prepare_domain.rb create mode 100644 app/interactions/domains/force_delete/set_force_delete.rb create mode 100644 app/interactions/domains/force_delete/set_status.rb delete mode 100644 app/interactions/force_delete_interaction/base.rb delete mode 100644 app/interactions/force_delete_interaction/check_discarded.rb delete mode 100644 app/interactions/force_delete_interaction/notify_by_email.rb delete mode 100644 app/interactions/force_delete_interaction/notify_registrar.rb delete mode 100644 app/interactions/force_delete_interaction/post_set_process.rb delete mode 100644 app/interactions/force_delete_interaction/prepare_domain.rb delete mode 100644 app/interactions/force_delete_interaction/set_force_delete.rb delete mode 100644 app/interactions/force_delete_interaction/set_status.rb diff --git a/app/interactions/cancel_force_delete_interaction/base.rb b/app/interactions/cancel_force_delete_interaction/base.rb deleted file mode 100644 index 595279d87..000000000 --- a/app/interactions/cancel_force_delete_interaction/base.rb +++ /dev/null @@ -1,7 +0,0 @@ -module CancelForceDeleteInteraction - class Base < ActiveInteraction::Base - object :domain, - class: Domain, - description: 'Domain to cancel ForceDelete on' - end -end diff --git a/app/interactions/cancel_force_delete_interaction/cancel_force_delete.rb b/app/interactions/cancel_force_delete_interaction/cancel_force_delete.rb deleted file mode 100644 index 2f45bf0e4..000000000 --- a/app/interactions/cancel_force_delete_interaction/cancel_force_delete.rb +++ /dev/null @@ -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 diff --git a/app/interactions/cancel_force_delete_interaction/clear_force_delete_data.rb b/app/interactions/cancel_force_delete_interaction/clear_force_delete_data.rb deleted file mode 100644 index ccc0714f7..000000000 --- a/app/interactions/cancel_force_delete_interaction/clear_force_delete_data.rb +++ /dev/null @@ -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 diff --git a/app/interactions/cancel_force_delete_interaction/notify_registrar.rb b/app/interactions/cancel_force_delete_interaction/notify_registrar.rb deleted file mode 100644 index 3ded4c489..000000000 --- a/app/interactions/cancel_force_delete_interaction/notify_registrar.rb +++ /dev/null @@ -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 diff --git a/app/interactions/cancel_force_delete_interaction/remove_force_delete_statuses.rb b/app/interactions/cancel_force_delete_interaction/remove_force_delete_statuses.rb deleted file mode 100644 index 1cc4989e5..000000000 --- a/app/interactions/cancel_force_delete_interaction/remove_force_delete_statuses.rb +++ /dev/null @@ -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 diff --git a/app/interactions/cancel_force_delete_interaction/restore_statuses_before_force_delete.rb b/app/interactions/cancel_force_delete_interaction/restore_statuses_before_force_delete.rb deleted file mode 100644 index 06b6bbd18..000000000 --- a/app/interactions/cancel_force_delete_interaction/restore_statuses_before_force_delete.rb +++ /dev/null @@ -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 diff --git a/app/interactions/domain_delete_confirm_interaction/send_request.rb b/app/interactions/domain_delete_confirm_interaction/send_request.rb deleted file mode 100644 index bbf4c8d9e..000000000 --- a/app/interactions/domain_delete_confirm_interaction/send_request.rb +++ /dev/null @@ -1,22 +0,0 @@ -module DomainDeleteConfirmInteraction - 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 diff --git a/app/interactions/domains/cancel_force_delete/base.rb b/app/interactions/domains/cancel_force_delete/base.rb new file mode 100644 index 000000000..b15a3ae77 --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/base.rb @@ -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 diff --git a/app/interactions/domains/cancel_force_delete/cancel_force_delete.rb b/app/interactions/domains/cancel_force_delete/cancel_force_delete.rb new file mode 100644 index 000000000..7c4ca90e1 --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/cancel_force_delete.rb @@ -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 diff --git a/app/interactions/domains/cancel_force_delete/clear_force_delete_data.rb b/app/interactions/domains/cancel_force_delete/clear_force_delete_data.rb new file mode 100644 index 000000000..066df04fd --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/clear_force_delete_data.rb @@ -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 diff --git a/app/interactions/domains/cancel_force_delete/notify_registrar.rb b/app/interactions/domains/cancel_force_delete/notify_registrar.rb new file mode 100644 index 000000000..0de69e13e --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/notify_registrar.rb @@ -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 diff --git a/app/interactions/domains/cancel_force_delete/remove_force_delete_statuses.rb b/app/interactions/domains/cancel_force_delete/remove_force_delete_statuses.rb new file mode 100644 index 000000000..c77820ecf --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/remove_force_delete_statuses.rb @@ -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 diff --git a/app/interactions/domains/cancel_force_delete/restore_statuses_before_force_delete.rb b/app/interactions/domains/cancel_force_delete/restore_statuses_before_force_delete.rb new file mode 100644 index 000000000..c55c06764 --- /dev/null +++ b/app/interactions/domains/cancel_force_delete/restore_statuses_before_force_delete.rb @@ -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 diff --git a/app/interactions/domains/delete_confirm/send_request.rb b/app/interactions/domains/delete_confirm/send_request.rb new file mode 100644 index 000000000..91afaefb8 --- /dev/null +++ b/app/interactions/domains/delete_confirm/send_request.rb @@ -0,0 +1,24 @@ +module Domains + module DeleteConfirm + 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 diff --git a/app/interactions/domains/force_delete/base.rb b/app/interactions/domains/force_delete/base.rb new file mode 100644 index 000000000..27601c1d2 --- /dev/null +++ b/app/interactions/domains/force_delete/base.rb @@ -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 diff --git a/app/interactions/domains/force_delete/check_discarded.rb b/app/interactions/domains/force_delete/check_discarded.rb new file mode 100644 index 000000000..cbb9c1dc6 --- /dev/null +++ b/app/interactions/domains/force_delete/check_discarded.rb @@ -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 diff --git a/app/interactions/domains/force_delete/notify_by_email.rb b/app/interactions/domains/force_delete/notify_by_email.rb new file mode 100644 index 000000000..b60f54a5e --- /dev/null +++ b/app/interactions/domains/force_delete/notify_by_email.rb @@ -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 diff --git a/app/interactions/domains/force_delete/notify_registrar.rb b/app/interactions/domains/force_delete/notify_registrar.rb new file mode 100644 index 000000000..522502640 --- /dev/null +++ b/app/interactions/domains/force_delete/notify_registrar.rb @@ -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 diff --git a/app/interactions/domains/force_delete/post_set_process.rb b/app/interactions/domains/force_delete/post_set_process.rb new file mode 100644 index 000000000..904149f93 --- /dev/null +++ b/app/interactions/domains/force_delete/post_set_process.rb @@ -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 diff --git a/app/interactions/domains/force_delete/prepare_domain.rb b/app/interactions/domains/force_delete/prepare_domain.rb new file mode 100644 index 000000000..74eea21ed --- /dev/null +++ b/app/interactions/domains/force_delete/prepare_domain.rb @@ -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 diff --git a/app/interactions/domains/force_delete/set_force_delete.rb b/app/interactions/domains/force_delete/set_force_delete.rb new file mode 100644 index 000000000..16a0b09fa --- /dev/null +++ b/app/interactions/domains/force_delete/set_force_delete.rb @@ -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 diff --git a/app/interactions/domains/force_delete/set_status.rb b/app/interactions/domains/force_delete/set_status.rb new file mode 100644 index 000000000..b0a53ad82 --- /dev/null +++ b/app/interactions/domains/force_delete/set_status.rb @@ -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 diff --git a/app/interactions/force_delete_interaction/base.rb b/app/interactions/force_delete_interaction/base.rb deleted file mode 100644 index 4764ce8fe..000000000 --- a/app/interactions/force_delete_interaction/base.rb +++ /dev/null @@ -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 - diff --git a/app/interactions/force_delete_interaction/check_discarded.rb b/app/interactions/force_delete_interaction/check_discarded.rb deleted file mode 100644 index e0c893294..000000000 --- a/app/interactions/force_delete_interaction/check_discarded.rb +++ /dev/null @@ -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 - diff --git a/app/interactions/force_delete_interaction/notify_by_email.rb b/app/interactions/force_delete_interaction/notify_by_email.rb deleted file mode 100644 index 541df258d..000000000 --- a/app/interactions/force_delete_interaction/notify_by_email.rb +++ /dev/null @@ -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 diff --git a/app/interactions/force_delete_interaction/notify_registrar.rb b/app/interactions/force_delete_interaction/notify_registrar.rb deleted file mode 100644 index 691e54f7e..000000000 --- a/app/interactions/force_delete_interaction/notify_registrar.rb +++ /dev/null @@ -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 diff --git a/app/interactions/force_delete_interaction/post_set_process.rb b/app/interactions/force_delete_interaction/post_set_process.rb deleted file mode 100644 index e51acf9b7..000000000 --- a/app/interactions/force_delete_interaction/post_set_process.rb +++ /dev/null @@ -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 diff --git a/app/interactions/force_delete_interaction/prepare_domain.rb b/app/interactions/force_delete_interaction/prepare_domain.rb deleted file mode 100644 index 97f364145..000000000 --- a/app/interactions/force_delete_interaction/prepare_domain.rb +++ /dev/null @@ -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 diff --git a/app/interactions/force_delete_interaction/set_force_delete.rb b/app/interactions/force_delete_interaction/set_force_delete.rb deleted file mode 100644 index 4608b5127..000000000 --- a/app/interactions/force_delete_interaction/set_force_delete.rb +++ /dev/null @@ -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 diff --git a/app/interactions/force_delete_interaction/set_status.rb b/app/interactions/force_delete_interaction/set_status.rb deleted file mode 100644 index 7d104aeee..000000000 --- a/app/interactions/force_delete_interaction/set_status.rb +++ /dev/null @@ -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 diff --git a/app/models/concerns/domain/force_delete.rb b/app/models/concerns/domain/force_delete.rb index ff869fc0a..6e0f6c886 100644 --- a/app/models/concerns/domain/force_delete.rb +++ b/app/models/concerns/domain/force_delete.rb @@ -53,13 +53,13 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength 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 diff --git a/app/models/domain.rb b/app/models/domain.rb index 1ef66ffab..dc7d86da8 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -418,7 +418,7 @@ class Domain < ApplicationRecord pending_delete_confirmation! save(validate: false) # should check if this did succeed - DomainDeleteConfirmInteraction::SendRequest.run(domain: self) + Domains::DeleteConfirm::SendRequest.run(domain: self) end def cancel_pending_delete diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index 7c205fa74..dcb9b80f6 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -113,7 +113,7 @@ class ForceDeleteTest < ActionMailer::TestCase def test_force_delete_cannot_be_scheduled_when_a_domain_is_discarded @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - result = ForceDeleteInteraction::SetForceDelete.run(domain: @domain, type: :fast_track) + result = Domains::ForceDelete::SetForceDelete.run(domain: @domain, type: :fast_track) assert_not result.valid? assert_not @domain.force_delete_scheduled? diff --git a/test/models/domain_test.rb b/test/models/domain_test.rb index cc88cf35f..ae12f4a1e 100644 --- a/test/models/domain_test.rb +++ b/test/models/domain_test.rb @@ -414,7 +414,7 @@ class DomainTest < ActiveSupport::TestCase force_delete_date: nil) @domain.update(template_name: 'legal_person') travel_to Time.zone.parse('2010-07-05') - ForceDeleteInteraction::SetForceDelete.run!(domain: @domain, type: :fast_track) + Domains::ForceDelete::SetForceDelete.run!(domain: @domain, type: :fast_track) assert(@domain.force_delete_scheduled?) other_registrant = Registrant.find_by(code: 'jane-001') @domain.pending_json['new_registrant_id'] = other_registrant.id From 8ff8aa78c8e12ae6523c3cc0ff1524b12de44d81 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 30 Nov 2020 16:08:32 +0500 Subject: [PATCH 029/106] Move interactor to namespace --- .../client_hold_interaction/base.rb | 8 --- .../process_client_hold.rb | 67 ------------------ .../set_client_hold.rb | 15 ---- app/interactions/domains/client_hold/base.rb | 10 +++ .../client_hold/process_client_hold.rb | 69 +++++++++++++++++++ .../domains/client_hold/set_client_hold.rb | 17 +++++ app/models/domain_cron.rb | 2 +- test/models/domain/force_delete_test.rb | 10 +-- 8 files changed, 102 insertions(+), 96 deletions(-) delete mode 100644 app/interactions/client_hold_interaction/base.rb delete mode 100644 app/interactions/client_hold_interaction/process_client_hold.rb delete mode 100644 app/interactions/client_hold_interaction/set_client_hold.rb create mode 100644 app/interactions/domains/client_hold/base.rb create mode 100644 app/interactions/domains/client_hold/process_client_hold.rb create mode 100644 app/interactions/domains/client_hold/set_client_hold.rb diff --git a/app/interactions/client_hold_interaction/base.rb b/app/interactions/client_hold_interaction/base.rb deleted file mode 100644 index be8b8b0a8..000000000 --- a/app/interactions/client_hold_interaction/base.rb +++ /dev/null @@ -1,8 +0,0 @@ -module ClientHoldInteraction - class Base < ActiveInteraction::Base - def to_stdout(message) - time = Time.zone.now.utc - STDOUT << "#{time} - #{message}\n" unless Rails.env.test? - end - end -end diff --git a/app/interactions/client_hold_interaction/process_client_hold.rb b/app/interactions/client_hold_interaction/process_client_hold.rb deleted file mode 100644 index 453c400cc..000000000 --- a/app/interactions/client_hold_interaction/process_client_hold.rb +++ /dev/null @@ -1,67 +0,0 @@ -module ClientHoldInteraction - 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 diff --git a/app/interactions/client_hold_interaction/set_client_hold.rb b/app/interactions/client_hold_interaction/set_client_hold.rb deleted file mode 100644 index d723d5cc8..000000000 --- a/app/interactions/client_hold_interaction/set_client_hold.rb +++ /dev/null @@ -1,15 +0,0 @@ -module ClientHoldInteraction - 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| - ClientHoldInteraction::ProcessClientHold.run(domain: domain) - end - - to_stdout('All client_hold setting are done\n') - end - end -end diff --git a/app/interactions/domains/client_hold/base.rb b/app/interactions/domains/client_hold/base.rb new file mode 100644 index 000000000..c3c626b79 --- /dev/null +++ b/app/interactions/domains/client_hold/base.rb @@ -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 diff --git a/app/interactions/domains/client_hold/process_client_hold.rb b/app/interactions/domains/client_hold/process_client_hold.rb new file mode 100644 index 000000000..8b8d60403 --- /dev/null +++ b/app/interactions/domains/client_hold/process_client_hold.rb @@ -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 diff --git a/app/interactions/domains/client_hold/set_client_hold.rb b/app/interactions/domains/client_hold/set_client_hold.rb new file mode 100644 index 000000000..0e54b531f --- /dev/null +++ b/app/interactions/domains/client_hold/set_client_hold.rb @@ -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 diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index 613762062..d09141d52 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -79,6 +79,6 @@ class DomainCron end def self.start_client_hold - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! end end diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index d9e7a3632..304a7a18b 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -206,7 +206,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-08-21') - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! @domain.reload assert_emails 1 @@ -227,7 +227,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-08-21') - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! @domain.reload assert_emails 1 @@ -244,7 +244,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :soft) travel_to Time.zone.parse('2010-07-06') - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! @domain.reload assert_not_includes(@domain.statuses, asserted_status) @@ -259,7 +259,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :fast_track) travel_to Time.zone.parse('2010-07-25') - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! @domain.reload assert_includes(@domain.statuses, asserted_status) @@ -275,7 +275,7 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.schedule_force_delete(type: :fast_track) travel_to Time.zone.parse('2010-07-06') - ClientHoldInteraction::SetClientHold.run! + Domains::ClientHold::SetClientHold.run! @domain.reload assert_not_includes(@domain.statuses, asserted_status) From cb7ff317e42a8a1dd2105834301e065e0ab676f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Mon, 30 Nov 2020 14:26:46 +0200 Subject: [PATCH 030/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44329c4d0..f418d4034 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From dc5bbb587f1490eb714742ff7db3acefc30a8c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 16:52:28 +0200 Subject: [PATCH 031/106] EPP: Show error when trying to remove unassigned domain status --- app/models/epp/domain.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index c46732712..a5922f48c 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -417,7 +417,7 @@ class Epp::Domain < Domain if statuses.include?(x) to_destroy << x else - add_epp_error('2303', 'status', x, [:domain_statuses, :not_found]) + add_epp_error('2303', 'status', x, [:statuses, :not_found]) end end @@ -432,7 +432,7 @@ class Epp::Domain < Domain frame.css('status').each do |x| unless DomainStatus::CLIENT_STATUSES.include?(x['s']) - add_epp_error('2303', 'status', x['s'], [:domain_statuses, :not_found]) + add_epp_error('2303', 'status', x['s'], [:statuses, :not_found]) next end From 490de2ee4bd89b83df277e8848efbdbe479edbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 17:05:21 +0200 Subject: [PATCH 032/106] Add test for unassigned domain status removal --- .../epp/domain/update/base_test.rb | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/integration/epp/domain/update/base_test.rb b/test/integration/epp/domain/update/base_test.rb index 6ce455948..14e806fca 100644 --- a/test/integration/epp/domain/update/base_test.rb +++ b/test/integration/epp/domain/update/base_test.rb @@ -503,6 +503,30 @@ class EppDomainUpdateBaseTest < EppTestCase assert_not_includes(@domain.statuses, DomainStatus::CLIENT_HOLD) end + def test_update_domain_returns_error_when_removing_unassigned_status + assert_not_includes(@domain.statuses, DomainStatus::CLIENT_HOLD) + request_xml = <<-XML + + + + + + #{@domain.name} + + + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + assert_epp_response :object_does_not_exist + end + private def assert_verification_and_notification_emails From e5a2a6cf0f33281c8f16874f5e3343bcf635465f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 17:10:04 +0200 Subject: [PATCH 033/106] Fix CC issues --- app/models/epp/domain.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index a5922f48c..7fb23a6e9 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -417,7 +417,7 @@ class Epp::Domain < Domain if statuses.include?(x) to_destroy << x else - add_epp_error('2303', 'status', x, [:statuses, :not_found]) + add_epp_error('2303', 'status', x, %i[statuses not_found]) end end @@ -432,7 +432,7 @@ class Epp::Domain < Domain frame.css('status').each do |x| unless DomainStatus::CLIENT_STATUSES.include?(x['s']) - add_epp_error('2303', 'status', x['s'], [:statuses, :not_found]) + add_epp_error('2303', 'status', x['s'], %i[statuses not_found]) next end From 512b181cd785e79d087f3d491d13ad6ad4787db8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 1 Dec 2020 10:00:04 +0200 Subject: [PATCH 034/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f418d4034..489ba94d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +01.12.2020 +* Refactored clientHold for interactors [#1751](https://github.com/internetee/registry/issues/1751) + 30.11.2020 * Refactor - interactors moved to domain space [#1762](https://github.com/internetee/registry/pull/1762) From c9d4aaded98c98e0b9dc38ed5d64861493ea0ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 30 Nov 2020 16:50:14 +0200 Subject: [PATCH 035/106] Fix registrant domain serializer --- .../api/v1/registrant/domains_controller.rb | 3 ++- lib/serializers/registrant_api/domain.rb | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/registrant/domains_controller.rb b/app/controllers/api/v1/registrant/domains_controller.rb index 390148488..73b534598 100644 --- a/app/controllers/api/v1/registrant/domains_controller.rb +++ b/app/controllers/api/v1/registrant/domains_controller.rb @@ -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'] }] }, @@ -20,7 +21,7 @@ module Api domains = current_user_domains serialized_domains = domains.limit(limit).offset(offset).map do |item| - serializer = Serializers::RegistrantApi::Domain.new(item, simplify: true) + serializer = Serializers::RegistrantApi::Domain.new(item, simplify: simple) serializer.to_json end diff --git a/lib/serializers/registrant_api/domain.rb b/lib/serializers/registrant_api/domain.rb index f0c9c1876..29362ad5c 100644 --- a/lib/serializers/registrant_api/domain.rb +++ b/lib/serializers/registrant_api/domain.rb @@ -9,18 +9,23 @@ module Serializers end def to_json - if simplify + if @simplify return { id: domain.uuid, name: domain.name, registered_at: domain.registered_at, valid_to: domain.valid_to, + outzone_at: domain.outzone_at, registrant_verification_asked_at: domain.registrant_verification_asked_at, statuses: domain.statuses, registrar: { name: domain.registrar.name, - website: domain.registrar.website - } + website: domain.registrar.website, + }, + registrant: { + name: domain.registrant.name, + id: domain.registrant.uuid, + }, } end From 15e090c3b1710f13ab63ecf25c2bfa5023e54043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 1 Dec 2020 12:53:30 +0200 Subject: [PATCH 036/106] Fix CC issue --- lib/serializers/registrant_api/domain.rb | 32 +++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/lib/serializers/registrant_api/domain.rb b/lib/serializers/registrant_api/domain.rb index 29362ad5c..f8d5bb830 100644 --- a/lib/serializers/registrant_api/domain.rb +++ b/lib/serializers/registrant_api/domain.rb @@ -8,26 +8,8 @@ module Serializers @simplify = simplify end - def to_json - if @simplify - return { - id: domain.uuid, - name: domain.name, - registered_at: domain.registered_at, - valid_to: domain.valid_to, - outzone_at: domain.outzone_at, - registrant_verification_asked_at: domain.registrant_verification_asked_at, - statuses: domain.statuses, - registrar: { - name: domain.registrar.name, - website: domain.registrar.website, - }, - registrant: { - name: domain.registrant.name, - id: domain.registrant.uuid, - }, - } - end + def to_json(_obj = nil) + return simple_object if @simplify { id: domain.uuid, @@ -70,6 +52,16 @@ module Serializers private + def simple_object + { + id: domain.uuid, name: domain.name, registered_at: domain.registered_at, + valid_to: domain.valid_to, outzone_at: domain.outzone_at, statuses: domain.statuses, + registrant_verification_asked_at: domain.registrant_verification_asked_at, + registrar: { name: domain.registrar.name, website: domain.registrar.website }, + registrant: { name: domain.registrant.name, id: domain.registrant.uuid } + } + end + def dnssec_keys domain.dnskeys.map do |key| "#{key.flags} #{key.protocol} #{key.alg} #{key.public_key}" From 8916cb29d1f631f690371abe24f6d80d50efd071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 1 Dec 2020 15:48:13 +0200 Subject: [PATCH 037/106] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 489ba94d3..9774d5cb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 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) From 15d2ffe200837ddfde536bfb22474ce3fb1099ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Thu, 3 Dec 2020 16:12:36 +0200 Subject: [PATCH 038/106] Registrant API: Return associated domains for contact query --- .../api/v1/registrant/contacts_controller.rb | 11 ++++++----- app/models/contact.rb | 13 +++++++++---- lib/serializers/registrant_api/contact.rb | 13 +++++++++---- lib/serializers/registrant_api/domain.rb | 3 ++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/v1/registrant/contacts_controller.rb b/app/controllers/api/v1/registrant/contacts_controller.rb index 10f9abacf..e11458ff8 100644 --- a/app/controllers/api/v1/registrant/contacts_controller.rb +++ b/app/controllers/api/v1/registrant/contacts_controller.rb @@ -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 diff --git a/app/models/contact.rb b/app/models/contact.rb index 8a154c50c..e30312b4a 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -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 ||= [] diff --git a/lib/serializers/registrant_api/contact.rb b/lib/serializers/registrant_api/contact.rb index dd36b4400..023544174 100644 --- a/lib/serializers/registrant_api/contact.rb +++ b/lib/serializers/registrant_api/contact.rb @@ -1,14 +1,15 @@ module Serializers module RegistrantApi class Contact - attr_reader :contact + attr_reader :contact, :links - def initialize(contact) + def initialize(contact, links) @contact = contact + @links = links end - def to_json - { + def to_json(_obj = nil) + obj = { id: contact.uuid, name: contact.name, code: contact.code, @@ -31,6 +32,10 @@ module Serializers statuses: contact.statuses, disclosed_attributes: contact.disclosed_attributes, } + + obj[:links] = contact.related_domains if @links + + obj end end end diff --git a/lib/serializers/registrant_api/domain.rb b/lib/serializers/registrant_api/domain.rb index f8d5bb830..2359d77c9 100644 --- a/lib/serializers/registrant_api/domain.rb +++ b/lib/serializers/registrant_api/domain.rb @@ -58,7 +58,8 @@ module Serializers valid_to: domain.valid_to, outzone_at: domain.outzone_at, statuses: domain.statuses, registrant_verification_asked_at: domain.registrant_verification_asked_at, registrar: { name: domain.registrar.name, website: domain.registrar.website }, - registrant: { name: domain.registrant.name, id: domain.registrant.uuid } + registrant: { name: domain.registrant.name, id: domain.registrant.uuid, + phone: domain.registrant.phone, email: domain.registrant.email } } end From 92b294e81b10e69109e20f2e3d1d54e0d81b6c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 4 Dec 2020 15:24:14 +0200 Subject: [PATCH 039/106] Reflect new behaviour of registrant API in tests --- .../api/registrant/registrant_api_domains_test.rb | 8 ++++---- test/lib/serializers/registrant_api/contact_test.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/api/registrant/registrant_api_domains_test.rb b/test/integration/api/registrant/registrant_api_domains_test.rb index 22516fecc..61d635e5f 100644 --- a/test/integration/api/registrant/registrant_api_domains_test.rb +++ b/test/integration/api/registrant/registrant_api_domains_test.rb @@ -50,10 +50,10 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest assert_equal(200, response.status) response_json = JSON.parse(response.body, symbolize_names: true) - array_of_domain_names = response_json.map { |x| x[:name] } + array_of_domain_names = response_json[:domains].map { |x| x[:name] } assert(array_of_domain_names.include?('hospital.test')) - array_of_domain_registrars = response_json.map { |x| x[:registrar] } + array_of_domain_registrars = response_json[:domains].map { |x| x[:registrar] } assert(array_of_domain_registrars.include?({name: 'Good Names', website: nil})) end @@ -63,12 +63,12 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(200, response.status) - assert_equal(2, response_json.count) + assert_equal(2, response_json[:domains].count) get '/api/v1/registrant/domains', headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) - assert_equal(4, response_json.count) + assert_equal(4, response_json[:domains].count) end def test_root_does_not_accept_limit_higher_than_200 diff --git a/test/lib/serializers/registrant_api/contact_test.rb b/test/lib/serializers/registrant_api/contact_test.rb index 165c91e00..8b84abd38 100644 --- a/test/lib/serializers/registrant_api/contact_test.rb +++ b/test/lib/serializers/registrant_api/contact_test.rb @@ -4,7 +4,7 @@ require 'serializers/registrant_api/contact' class SerializersRegistrantApiContactTest < ActiveSupport::TestCase def setup @contact = contacts(:william) - @serializer = Serializers::RegistrantApi::Contact.new(@contact) + @serializer = Serializers::RegistrantApi::Contact.new(@contact, false) @json = @serializer.to_json end From 36ff1fcf39b7f6ddf48b9c6157be39ac0760f1f2 Mon Sep 17 00:00:00 2001 From: Georg Date: Tue, 17 Nov 2020 14:27:12 +0200 Subject: [PATCH 040/106] Create ruby.yml example workflow Update ruby.yml limit builds Update ruby.yml postgres service Update ruby.yml pg_port copy config files Update ruby.yml Update ruby.yml Update database_travis.yml Update ruby.yml Update ruby.yml bump wkhtmltopdf-binary Unlock gem 'wkhtmltopdf-binary' Update ruby.yml Update ruby.yml Update ruby.yml remove Lockfile restore Gemfile test only ubuntu-18.04 bundle env remove deploy deps remove mina dep use rexml from bundle rather then std-lib to support ruby 3.0 install rexml drop ruby 3.0, cleanup workflow fix codeclimate sorting issue Codeclimate reporting stop using deprecated set-env use simplecov formater simplecov in after-build fix yaml syntax run in debug mode Set correct env var to run coverage cleanup, provide CC_TEST_REPORTER_ID secret combine multiple results more variables pull/commit different envs Change test command to get more coverage --- .github/workflows/ruby.yml | 117 +++++++++++++++++++++++++++++++++++++ Gemfile | 6 +- Gemfile.lock | 14 +---- config/database_travis.yml | 2 +- test/test_helper.rb | 1 + 5 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/ruby.yml diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 000000000..eea0ccc03 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -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 + diff --git a/Gemfile b/Gemfile index 7ae8d4ef6..9bbcba254 100644 --- a/Gemfile +++ b/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' diff --git a/Gemfile.lock b/Gemfile.lock index 72c716aae..2a0bb55b1 100644 --- a/Gemfile.lock +++ b/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) diff --git a/config/database_travis.yml b/config/database_travis.yml index b79e2c453..48ffd5e27 100644 --- a/config/database_travis.yml +++ b/config/database_travis.yml @@ -4,7 +4,7 @@ default: &default encoding: unicode pool: 5 username: postgres - password: + password: password test: <<: *default diff --git a/test/test_helper.rb b/test/test_helper.rb index 459d4f8f5..a1634f717 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,6 +6,7 @@ if ENV['COVERAGE'] add_filter '/lib/core_monkey_patches/' add_filter '/lib/daemons/' add_filter '/lib/gem_monkey_patches/' + add_filter '/lib/tasks/' end end From 1b8906a9ccb70d774357f67276384182baf58417 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 7 Dec 2020 13:55:50 +0500 Subject: [PATCH 041/106] Remove Travis support --- .travis.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 23d4ab6b1..000000000 --- a/.travis.yml +++ /dev/null @@ -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 From d4063349264a9ac3c5d19b4b1af3c6fdd1fe7465 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 25 Nov 2020 14:26:53 +0500 Subject: [PATCH 042/106] Move DomainDelete to interactor design pattern --- .../domain_delete_interaction/base.rb | 7 +++++++ .../domain_delete_interaction/delete.rb | 11 ++++++++++ .../nofity_registrar.rb | 12 +++++++++++ app/jobs/domain_delete_job.rb | 21 ++++++++++--------- 4 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 app/interactions/domain_delete_interaction/base.rb create mode 100644 app/interactions/domain_delete_interaction/delete.rb create mode 100644 app/interactions/domain_delete_interaction/nofity_registrar.rb diff --git a/app/interactions/domain_delete_interaction/base.rb b/app/interactions/domain_delete_interaction/base.rb new file mode 100644 index 000000000..b2895e1d1 --- /dev/null +++ b/app/interactions/domain_delete_interaction/base.rb @@ -0,0 +1,7 @@ +module DomainDeleteInteraction + class Base < ActiveInteraction::Base + object :domain, + class: Domain, + description: 'Domain to delete' + end +end diff --git a/app/interactions/domain_delete_interaction/delete.rb b/app/interactions/domain_delete_interaction/delete.rb new file mode 100644 index 000000000..181431ca1 --- /dev/null +++ b/app/interactions/domain_delete_interaction/delete.rb @@ -0,0 +1,11 @@ +module DomainDeleteInteraction + class Delete < :Base + def execute + ::PaperTrail.request.whodunnit = "interaction - #{self.class.name}" + WhoisRecord.where(domain_id: domain.id).destroy_all + + domain.destroy + compose(NotifyRegistrar, inputs) + end + end +end diff --git a/app/interactions/domain_delete_interaction/nofity_registrar.rb b/app/interactions/domain_delete_interaction/nofity_registrar.rb new file mode 100644 index 000000000..81a66e6b0 --- /dev/null +++ b/app/interactions/domain_delete_interaction/nofity_registrar.rb @@ -0,0 +1,12 @@ +module DomainDeleteInteraction + class NotifyRegistrar < Delete + 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 diff --git a/app/jobs/domain_delete_job.rb b/app/jobs/domain_delete_job.rb index 43e0bb844..a41a27f05 100644 --- a/app/jobs/domain_delete_job.rb +++ b/app/jobs/domain_delete_job.rb @@ -3,15 +3,16 @@ 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 - ) + DomainDeleteInteraction::Delete.run(domain: domain) + # ::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 + # ) end end From 4c7f9f202601bed993a9811d56993b8f7cc04070 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 25 Nov 2020 17:01:58 +0500 Subject: [PATCH 043/106] Add interactor tests --- .../domain_delete_interaction/delete.rb | 4 +-- ...ofity_registrar.rb => notify_registrar.rb} | 2 +- app/jobs/domain_delete_job.rb | 10 -------- .../domain_delete_interaction_delete_test.rb | 25 +++++++++++++++++++ 4 files changed, 28 insertions(+), 13 deletions(-) rename app/interactions/domain_delete_interaction/{nofity_registrar.rb => notify_registrar.rb} (90%) create mode 100644 test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb diff --git a/app/interactions/domain_delete_interaction/delete.rb b/app/interactions/domain_delete_interaction/delete.rb index 181431ca1..1a74aae50 100644 --- a/app/interactions/domain_delete_interaction/delete.rb +++ b/app/interactions/domain_delete_interaction/delete.rb @@ -1,11 +1,11 @@ module DomainDeleteInteraction - class Delete < :Base + class Delete < Base def execute ::PaperTrail.request.whodunnit = "interaction - #{self.class.name}" WhoisRecord.where(domain_id: domain.id).destroy_all domain.destroy - compose(NotifyRegistrar, inputs) + compose(DomainDeleteInteraction::NotifyRegistrar, inputs) end end end diff --git a/app/interactions/domain_delete_interaction/nofity_registrar.rb b/app/interactions/domain_delete_interaction/notify_registrar.rb similarity index 90% rename from app/interactions/domain_delete_interaction/nofity_registrar.rb rename to app/interactions/domain_delete_interaction/notify_registrar.rb index 81a66e6b0..990f74de6 100644 --- a/app/interactions/domain_delete_interaction/nofity_registrar.rb +++ b/app/interactions/domain_delete_interaction/notify_registrar.rb @@ -1,5 +1,5 @@ module DomainDeleteInteraction - class NotifyRegistrar < Delete + class NotifyRegistrar < Base def execute bye_bye = domain.versions.last domain.registrar.notifications.create!( diff --git a/app/jobs/domain_delete_job.rb b/app/jobs/domain_delete_job.rb index a41a27f05..49ef23aa3 100644 --- a/app/jobs/domain_delete_job.rb +++ b/app/jobs/domain_delete_job.rb @@ -4,15 +4,5 @@ class DomainDeleteJob < Que::Job domain = Domain.find(domain_id) DomainDeleteInteraction::Delete.run(domain: domain) - # ::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 - # ) end end diff --git a/test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb b/test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb new file mode 100644 index 000000000..a44140b34 --- /dev/null +++ b/test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +class DomainDeleteInteractionDeleteTest < ActiveSupport::TestCase + setup do + @domain = domains(:shop) + end + + def test_discards_domains_with_past_delete_date + @domain.update!(delete_date: '2010-07-04') + travel_to Time.zone.parse('2010-07-05') + + DomainDeleteInteraction::Delete.run(domain: @domain) + + assert @domain.destroyed? + end + + def test_sends_notification + @domain.update!(delete_date: '2010-07-04') + travel_to Time.zone.parse('2010-07-05') + + assert_difference '@domain.registrar.notifications.count', 1 do + DomainDeleteInteraction::Delete.run(domain: @domain) + end + end +end From 30ddf83ee42dd21cc4cfc77a6addadda4a6ea16f Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 30 Nov 2020 16:20:24 +0500 Subject: [PATCH 044/106] Move interactor to namespace --- app/interactions/domain_delete_interaction/base.rb | 7 ------- .../domain_delete_interaction/delete.rb | 11 ----------- .../domain_delete_interaction/notify_registrar.rb | 12 ------------ app/interactions/domains/delete/base.rb | 9 +++++++++ app/interactions/domains/delete/do_delete.rb | 13 +++++++++++++ .../domains/delete/notify_registrar.rb | 14 ++++++++++++++ app/jobs/domain_delete_job.rb | 2 +- ...action_delete_test.rb => domain_delete_test.rb} | 6 +++--- 8 files changed, 40 insertions(+), 34 deletions(-) delete mode 100644 app/interactions/domain_delete_interaction/base.rb delete mode 100644 app/interactions/domain_delete_interaction/delete.rb delete mode 100644 app/interactions/domain_delete_interaction/notify_registrar.rb create mode 100644 app/interactions/domains/delete/base.rb create mode 100644 app/interactions/domains/delete/do_delete.rb create mode 100644 app/interactions/domains/delete/notify_registrar.rb rename test/interactions/domain_delete_interaction/{domain_delete_interaction_delete_test.rb => domain_delete_test.rb} (71%) diff --git a/app/interactions/domain_delete_interaction/base.rb b/app/interactions/domain_delete_interaction/base.rb deleted file mode 100644 index b2895e1d1..000000000 --- a/app/interactions/domain_delete_interaction/base.rb +++ /dev/null @@ -1,7 +0,0 @@ -module DomainDeleteInteraction - class Base < ActiveInteraction::Base - object :domain, - class: Domain, - description: 'Domain to delete' - end -end diff --git a/app/interactions/domain_delete_interaction/delete.rb b/app/interactions/domain_delete_interaction/delete.rb deleted file mode 100644 index 1a74aae50..000000000 --- a/app/interactions/domain_delete_interaction/delete.rb +++ /dev/null @@ -1,11 +0,0 @@ -module DomainDeleteInteraction - class Delete < Base - def execute - ::PaperTrail.request.whodunnit = "interaction - #{self.class.name}" - WhoisRecord.where(domain_id: domain.id).destroy_all - - domain.destroy - compose(DomainDeleteInteraction::NotifyRegistrar, inputs) - end - end -end diff --git a/app/interactions/domain_delete_interaction/notify_registrar.rb b/app/interactions/domain_delete_interaction/notify_registrar.rb deleted file mode 100644 index 990f74de6..000000000 --- a/app/interactions/domain_delete_interaction/notify_registrar.rb +++ /dev/null @@ -1,12 +0,0 @@ -module DomainDeleteInteraction - 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 diff --git a/app/interactions/domains/delete/base.rb b/app/interactions/domains/delete/base.rb new file mode 100644 index 000000000..434712f72 --- /dev/null +++ b/app/interactions/domains/delete/base.rb @@ -0,0 +1,9 @@ +module Domains + module Delete + class Base < ActiveInteraction::Base + object :domain, + class: Domain, + description: 'Domain to delete' + end + end +end diff --git a/app/interactions/domains/delete/do_delete.rb b/app/interactions/domains/delete/do_delete.rb new file mode 100644 index 000000000..202c36938 --- /dev/null +++ b/app/interactions/domains/delete/do_delete.rb @@ -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 diff --git a/app/interactions/domains/delete/notify_registrar.rb b/app/interactions/domains/delete/notify_registrar.rb new file mode 100644 index 000000000..d6af00fd8 --- /dev/null +++ b/app/interactions/domains/delete/notify_registrar.rb @@ -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 diff --git a/app/jobs/domain_delete_job.rb b/app/jobs/domain_delete_job.rb index 49ef23aa3..5577908c6 100644 --- a/app/jobs/domain_delete_job.rb +++ b/app/jobs/domain_delete_job.rb @@ -3,6 +3,6 @@ class DomainDeleteJob < Que::Job def run(domain_id) domain = Domain.find(domain_id) - DomainDeleteInteraction::Delete.run(domain: domain) + Domains::Delete::DoDelete.run(domain: domain) end end diff --git a/test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb b/test/interactions/domain_delete_interaction/domain_delete_test.rb similarity index 71% rename from test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb rename to test/interactions/domain_delete_interaction/domain_delete_test.rb index a44140b34..9582fae03 100644 --- a/test/interactions/domain_delete_interaction/domain_delete_interaction_delete_test.rb +++ b/test/interactions/domain_delete_interaction/domain_delete_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class DomainDeleteInteractionDeleteTest < ActiveSupport::TestCase +class DomainDeleteTest < ActiveSupport::TestCase setup do @domain = domains(:shop) end @@ -9,7 +9,7 @@ class DomainDeleteInteractionDeleteTest < ActiveSupport::TestCase @domain.update!(delete_date: '2010-07-04') travel_to Time.zone.parse('2010-07-05') - DomainDeleteInteraction::Delete.run(domain: @domain) + Domains::Delete::DoDelete.run(domain: @domain) assert @domain.destroyed? end @@ -19,7 +19,7 @@ class DomainDeleteInteractionDeleteTest < ActiveSupport::TestCase travel_to Time.zone.parse('2010-07-05') assert_difference '@domain.registrar.notifications.count', 1 do - DomainDeleteInteraction::Delete.run(domain: @domain) + Domains::Delete::DoDelete.run(domain: @domain) end end end From b4e26952d682342fcbcac42695762ab0a0b1a6c6 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 1 Dec 2020 18:34:43 +0500 Subject: [PATCH 045/106] Fix domain deletion deadline --- app/models/concerns/domain/deletable.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/domain/deletable.rb b/app/models/concerns/domain/deletable.rb index bd01ab1c9..81518c739 100644 --- a/app/models/concerns/domain/deletable.rb +++ b/app/models/concerns/domain/deletable.rb @@ -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 \ No newline at end of file +end From 31bfe19d77c254e214c25f9efb7ecc90c1dfb8a6 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 26 Nov 2020 14:07:02 +0500 Subject: [PATCH 046/106] Move DomainUpdateConfirm from Que to ActiveJob --- app/jobs/application_job.rb | 2 ++ app/jobs/domain_update_confirm_job.rb | 7 ++++--- app/models/registrant_verification.rb | 4 ++-- test/jobs/domain_update_confirm_job_test.rb | 8 ++++---- 4 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 app/jobs/application_job.rb diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 000000000..a009ace51 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/jobs/domain_update_confirm_job.rb b/app/jobs/domain_update_confirm_job.rb index f3665f1e8..2025354e6 100644 --- a/app/jobs/domain_update_confirm_job.rb +++ b/app/jobs/domain_update_confirm_job.rb @@ -1,5 +1,7 @@ -class DomainUpdateConfirmJob < Que::Job - def run(domain_id, action, initiator = nil) +class DomainUpdateConfirmJob < ApplicationJob + queue_as :default + + def perform(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 @@ -27,7 +29,6 @@ class DomainUpdateConfirmJob < Que::Job domain.preclean_pendings domain.clean_pendings! end - destroy # it's best to destroy the job in the same transaction end end diff --git a/app/models/registrant_verification.rb b/app/models/registrant_verification.rb index 097f0cfa9..7e238cecc 100644 --- a/app/models/registrant_verification.rb +++ b/app/models/registrant_verification.rb @@ -18,13 +18,13 @@ 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) diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index 9cca81eb7..f01e7c41e 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -20,7 +20,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase end def test_rejected_registrant_verification_notifies_registrar - DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) last_registrar_notification = @domain.registrar.notifications.last assert_equal(last_registrar_notification.attached_obj_id, @domain.id) @@ -28,7 +28,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase end def test_accepted_registrant_verification_notifies_registrar - DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::CONFIRMED) last_registrar_notification = @domain.registrar.notifications.last assert_equal(last_registrar_notification.attached_obj_id, @domain.id) @@ -44,7 +44,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase @domain.update(pending_json: @domain.pending_json) @domain.reload - DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::CONFIRMED) @domain.reload assert_equal @domain.registrant.code, @new_registrant.code @@ -58,7 +58,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase @domain.pending_json['frame'] = epp_xml @domain.update(pending_json: @domain.pending_json) - DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) @domain.reload assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION From 4b7cffbb572ea1e63e8d02962df994791770ef8b Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 26 Nov 2020 15:01:09 +0500 Subject: [PATCH 047/106] Move functionality from job to interactor --- .../domain_update_confirm_interaction/base.rb | 22 ++++++++++++ .../process_action.rb | 15 ++++++++ .../process_update_confirmed.rb | 20 +++++++++++ .../process_update_rejected.rb | 16 +++++++++ app/jobs/domain_update_confirm_job.rb | 36 +++---------------- 5 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 app/interactions/domain_update_confirm_interaction/base.rb create mode 100644 app/interactions/domain_update_confirm_interaction/process_action.rb create mode 100644 app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb create mode 100644 app/interactions/domain_update_confirm_interaction/process_update_rejected.rb diff --git a/app/interactions/domain_update_confirm_interaction/base.rb b/app/interactions/domain_update_confirm_interaction/base.rb new file mode 100644 index 000000000..18a96fc99 --- /dev/null +++ b/app/interactions/domain_update_confirm_interaction/base.rb @@ -0,0 +1,22 @@ +module DomainUpdateConfirmInteraction + 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) + if domain.errors.any? + message = "domain #{domain.name} failed with errors #{domain.errors.full_messages}" + throw message + end + end + end +end + diff --git a/app/interactions/domain_update_confirm_interaction/process_action.rb b/app/interactions/domain_update_confirm_interaction/process_action.rb new file mode 100644 index 000000000..9def919d1 --- /dev/null +++ b/app/interactions/domain_update_confirm_interaction/process_action.rb @@ -0,0 +1,15 @@ +module DomainUpdateConfirmInteraction + 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 diff --git a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb new file mode 100644 index 000000000..bb235dcb9 --- /dev/null +++ b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb @@ -0,0 +1,20 @@ +module DomainUpdateConfirmInteraction + class ProcessUpdateConfirmed < Base + def execute + ActiveRecord::Base.transaction do + domain.is_admin = true + old_registrant = domain.registrant + domain.notify_registrar(:poll_pending_update_confirmed_by_registrant) + + domain.apply_pending_update! + raise_errors!(domain) + + domain.clean_pendings! + raise_errors!(domain) + RegistrantChange.new(domain: domain, old_registrant: old_registrant).confirm + end + end + + + end +end diff --git a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb new file mode 100644 index 000000000..5875d17d5 --- /dev/null +++ b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb @@ -0,0 +1,16 @@ +module DomainUpdateConfirmInteraction + class ProcessUpdateRejected < Base + def execute + ActiveRecord::Base.transaction do + 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 + end + end +end diff --git a/app/jobs/domain_update_confirm_job.rb b/app/jobs/domain_update_confirm_job.rb index 2025354e6..8f1fd1688 100644 --- a/app/jobs/domain_update_confirm_job.rb +++ b/app/jobs/domain_update_confirm_job.rb @@ -2,37 +2,9 @@ class DomainUpdateConfirmJob < ApplicationJob queue_as :default def perform(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) - - 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 - end - end - - def raise_errors!(domain) - throw "domain #{domain.name} failed with errors #{domain.errors.full_messages}" if domain.errors.any? + domain = Epp::Domain.find(domain_id) + DomainUpdateConfirmInteraction::ProcessAction.run(domain: domain, + action: action, + initiator: initiator) end end From 8ef748fc7d61e34e784529722add638d1862d380 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 26 Nov 2020 15:21:22 +0500 Subject: [PATCH 048/106] Move apply_pending_update! method from model to interactor --- .codeclimate.yml | 3 ++ .../domain_update_confirm_interaction/base.rb | 17 +++++--- .../process_update_confirmed.rb | 42 ++++++++++++++++--- .../process_update_rejected.rb | 2 +- app/models/domain.rb | 3 ++ app/models/epp/domain.rb | 19 --------- 6 files changed, 56 insertions(+), 30 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 2bc90b200..d079d891f 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -20,6 +20,9 @@ plugins: channel: eslint-5 fixme: enabled: true + checks: + TODO: + enabled: false rubocop: enabled: true channel: rubocop-0-74 diff --git a/app/interactions/domain_update_confirm_interaction/base.rb b/app/interactions/domain_update_confirm_interaction/base.rb index 18a96fc99..d78f3a6a9 100644 --- a/app/interactions/domain_update_confirm_interaction/base.rb +++ b/app/interactions/domain_update_confirm_interaction/base.rb @@ -12,11 +12,18 @@ module DomainUpdateConfirmInteraction RegistrantVerification::REJECTED] } def raise_errors!(domain) - if domain.errors.any? - message = "domain #{domain.name} failed with errors #{domain.errors.full_messages}" - throw message - end + 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 end end - diff --git a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb index bb235dcb9..43c053ba2 100644 --- a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb +++ b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb @@ -4,17 +4,49 @@ module DomainUpdateConfirmInteraction ActiveRecord::Base.transaction do domain.is_admin = true old_registrant = domain.registrant - domain.notify_registrar(:poll_pending_update_confirmed_by_registrant) + notify_registrar(:poll_pending_update_confirmed_by_registrant) - domain.apply_pending_update! - raise_errors!(domain) - - domain.clean_pendings! + 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! + domain.save! + WhoisRecord.find_by(domain_id: domain.id).save # need to reload model + end + + def preclean_pendings + domain.registrant_verification_token = nil + domain.registrant_verification_asked_at = nil + end + + def update_domain + user = ApiUser.find(domain.pending_json['current_user_id']) + frame = Nokogiri::XML(domain.pending_json['frame']) + domain.upid = user.registrar.id if user.registrar + domain.update(frame, user, false) + end + + def clean_pendings! + domain.up_date = Time.zone.now + domain.registrant_verification_token = nil + domain.registrant_verification_asked_at = nil + domain.pending_json = {} + clear_statuses + 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 diff --git a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb index 5875d17d5..09da14971 100644 --- a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb +++ b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb @@ -6,7 +6,7 @@ module DomainUpdateConfirmInteraction registrar: domain.registrar, registrant: domain.registrant).deliver_now - domain.notify_registrar(:poll_pending_update_rejected_by_registrant) + notify_registrar(:poll_pending_update_rejected_by_registrant) domain.preclean_pendings domain.clean_pendings! diff --git a/app/models/domain.rb b/app/models/domain.rb index dc7d86da8..d2f555977 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -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) diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 7fb23a6e9..d8f5f2bb9 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -508,25 +508,6 @@ class Epp::Domain < Domain errors.empty? && super(at) end - def apply_pending_update! - preclean_pendings - user = ApiUser.find(pending_json['current_user_id']) - frame = Nokogiri::XML(pending_json['frame']) - - self.statuses.delete(DomainStatus::PENDING_UPDATE) - self.upid = user.registrar.id if user.registrar - self.up_date = Time.zone.now - - return unless update(frame, user, false) - clean_pendings! - - save! - - WhoisRecord.find_by(domain_id: id).save # need to reload model - - true - end - def apply_pending_delete! preclean_pendings statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION) From 6f0b8b15a3c4994b1719c361c2e447ec5cf609c1 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 26 Nov 2020 16:13:50 +0500 Subject: [PATCH 049/106] Move clean pendings used from model to interactor base --- .../domain_update_confirm_interaction/base.rb | 20 ++++++++++++++++ .../process_update_confirmed.rb | 24 +++---------------- .../process_update_rejected.rb | 4 ++-- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/app/interactions/domain_update_confirm_interaction/base.rb b/app/interactions/domain_update_confirm_interaction/base.rb index d78f3a6a9..1a1f61b12 100644 --- a/app/interactions/domain_update_confirm_interaction/base.rb +++ b/app/interactions/domain_update_confirm_interaction/base.rb @@ -25,5 +25,25 @@ module DomainUpdateConfirmInteraction 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.registrant_verification_token = nil + domain.registrant_verification_asked_at = nil + domain.pending_json = {} + clear_statuses + 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 diff --git a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb index 43c053ba2..0e173c533 100644 --- a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb +++ b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb @@ -21,32 +21,14 @@ module DomainUpdateConfirmInteraction WhoisRecord.find_by(domain_id: domain.id).save # need to reload model end - def preclean_pendings - domain.registrant_verification_token = nil - domain.registrant_verification_asked_at = nil - end - + # rubocop:disable Metrics/AbcSize def update_domain user = ApiUser.find(domain.pending_json['current_user_id']) frame = Nokogiri::XML(domain.pending_json['frame']) domain.upid = user.registrar.id if user.registrar + domain.up_date = Time.zone.now domain.update(frame, user, false) end - - def clean_pendings! - domain.up_date = Time.zone.now - domain.registrant_verification_token = nil - domain.registrant_verification_asked_at = nil - domain.pending_json = {} - clear_statuses - 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 + # rubocop:enable Metrics/AbcSize end end diff --git a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb index 09da14971..390f8db49 100644 --- a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb +++ b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb @@ -8,8 +8,8 @@ module DomainUpdateConfirmInteraction notify_registrar(:poll_pending_update_rejected_by_registrant) - domain.preclean_pendings - domain.clean_pendings! + preclean_pendings + clean_pendings! end end end From 42012863e23a8e2b3a31ad08a84aa1d325f640f6 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 30 Nov 2020 17:53:36 +0500 Subject: [PATCH 050/106] Move interactor to the Domains namespace --- .../domain_update_confirm_interaction/base.rb | 49 ------------------ .../process_action.rb | 15 ------ .../process_update_confirmed.rb | 34 ------------- .../process_update_rejected.rb | 16 ------ .../domains/update_confirm/base.rb | 51 +++++++++++++++++++ .../domains/update_confirm/process_action.rb | 17 +++++++ .../process_update_confirmed.rb | 36 +++++++++++++ .../update_confirm/process_update_rejected.rb | 18 +++++++ app/jobs/domain_update_confirm_job.rb | 6 +-- 9 files changed, 125 insertions(+), 117 deletions(-) delete mode 100644 app/interactions/domain_update_confirm_interaction/base.rb delete mode 100644 app/interactions/domain_update_confirm_interaction/process_action.rb delete mode 100644 app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb delete mode 100644 app/interactions/domain_update_confirm_interaction/process_update_rejected.rb create mode 100644 app/interactions/domains/update_confirm/base.rb create mode 100644 app/interactions/domains/update_confirm/process_action.rb create mode 100644 app/interactions/domains/update_confirm/process_update_confirmed.rb create mode 100644 app/interactions/domains/update_confirm/process_update_rejected.rb diff --git a/app/interactions/domain_update_confirm_interaction/base.rb b/app/interactions/domain_update_confirm_interaction/base.rb deleted file mode 100644 index 1a1f61b12..000000000 --- a/app/interactions/domain_update_confirm_interaction/base.rb +++ /dev/null @@ -1,49 +0,0 @@ -module DomainUpdateConfirmInteraction - 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.registrant_verification_token = nil - domain.registrant_verification_asked_at = nil - domain.pending_json = {} - clear_statuses - 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 diff --git a/app/interactions/domain_update_confirm_interaction/process_action.rb b/app/interactions/domain_update_confirm_interaction/process_action.rb deleted file mode 100644 index 9def919d1..000000000 --- a/app/interactions/domain_update_confirm_interaction/process_action.rb +++ /dev/null @@ -1,15 +0,0 @@ -module DomainUpdateConfirmInteraction - 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 diff --git a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb b/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb deleted file mode 100644 index 0e173c533..000000000 --- a/app/interactions/domain_update_confirm_interaction/process_update_confirmed.rb +++ /dev/null @@ -1,34 +0,0 @@ -module DomainUpdateConfirmInteraction - class ProcessUpdateConfirmed < Base - def execute - ActiveRecord::Base.transaction do - domain.is_admin = true - 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! - domain.save! - - WhoisRecord.find_by(domain_id: domain.id).save # need to reload model - end - - # rubocop:disable Metrics/AbcSize - def update_domain - user = ApiUser.find(domain.pending_json['current_user_id']) - frame = Nokogiri::XML(domain.pending_json['frame']) - domain.upid = user.registrar.id if user.registrar - domain.up_date = Time.zone.now - domain.update(frame, user, false) - end - # rubocop:enable Metrics/AbcSize - end -end diff --git a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb b/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb deleted file mode 100644 index 390f8db49..000000000 --- a/app/interactions/domain_update_confirm_interaction/process_update_rejected.rb +++ /dev/null @@ -1,16 +0,0 @@ -module DomainUpdateConfirmInteraction - 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 diff --git a/app/interactions/domains/update_confirm/base.rb b/app/interactions/domains/update_confirm/base.rb new file mode 100644 index 000000000..ab5584c03 --- /dev/null +++ b/app/interactions/domains/update_confirm/base.rb @@ -0,0 +1,51 @@ +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.registrant_verification_token = nil + domain.registrant_verification_asked_at = nil + domain.pending_json = {} + clear_statuses + 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 diff --git a/app/interactions/domains/update_confirm/process_action.rb b/app/interactions/domains/update_confirm/process_action.rb new file mode 100644 index 000000000..6ef8d0fe6 --- /dev/null +++ b/app/interactions/domains/update_confirm/process_action.rb @@ -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 diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb new file mode 100644 index 000000000..0402994dd --- /dev/null +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -0,0 +1,36 @@ +module Domains + module UpdateConfirm + class ProcessUpdateConfirmed < Base + def execute + ActiveRecord::Base.transaction do + domain.is_admin = true + 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! + domain.save! + + WhoisRecord.find_by(domain_id: domain.id).save # need to reload model + end + + # rubocop:disable Metrics/AbcSize + def update_domain + user = ApiUser.find(domain.pending_json['current_user_id']) + frame = Nokogiri::XML(domain.pending_json['frame']) + domain.upid = user.registrar.id if user.registrar + domain.up_date = Time.zone.now + domain.update(frame, user, false) + end + # rubocop:enable Metrics/AbcSize + end + end +end diff --git a/app/interactions/domains/update_confirm/process_update_rejected.rb b/app/interactions/domains/update_confirm/process_update_rejected.rb new file mode 100644 index 000000000..1d7b75b0e --- /dev/null +++ b/app/interactions/domains/update_confirm/process_update_rejected.rb @@ -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 diff --git a/app/jobs/domain_update_confirm_job.rb b/app/jobs/domain_update_confirm_job.rb index 8f1fd1688..403318ca6 100644 --- a/app/jobs/domain_update_confirm_job.rb +++ b/app/jobs/domain_update_confirm_job.rb @@ -3,8 +3,8 @@ class DomainUpdateConfirmJob < ApplicationJob def perform(domain_id, action, initiator = nil) domain = Epp::Domain.find(domain_id) - DomainUpdateConfirmInteraction::ProcessAction.run(domain: domain, - action: action, - initiator: initiator) + Domains::UpdateConfirm::ProcessAction.run(domain: domain, + action: action, + initiator: initiator) end end From a0bc60ac74a1b29e5f18274f8d8cdd9896d8fb80 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 1 Dec 2020 18:28:34 +0500 Subject: [PATCH 051/106] Fix rejecting changes clearance --- .../domains/update_confirm/process_update_rejected.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/interactions/domains/update_confirm/process_update_rejected.rb b/app/interactions/domains/update_confirm/process_update_rejected.rb index 1d7b75b0e..19969d970 100644 --- a/app/interactions/domains/update_confirm/process_update_rejected.rb +++ b/app/interactions/domains/update_confirm/process_update_rejected.rb @@ -11,6 +11,7 @@ module Domains preclean_pendings clean_pendings! + domain.save! end end end From 6ab08dbd673e2b9d9e8801ec23ff58e903b6d155 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 2 Dec 2020 13:51:49 +0500 Subject: [PATCH 052/106] Fix rejecting updates --- .../process_update_confirmed.rb | 2 +- .../update_confirm/process_update_rejected.rb | 2 +- test/jobs/domain_update_confirm_job_test.rb | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index 0402994dd..a4ceb1d3e 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -17,7 +17,7 @@ module Domains preclean_pendings update_domain clean_pendings! - domain.save! + domain.save(validate: false) WhoisRecord.find_by(domain_id: domain.id).save # need to reload model end diff --git a/app/interactions/domains/update_confirm/process_update_rejected.rb b/app/interactions/domains/update_confirm/process_update_rejected.rb index 19969d970..5ce818e66 100644 --- a/app/interactions/domains/update_confirm/process_update_rejected.rb +++ b/app/interactions/domains/update_confirm/process_update_rejected.rb @@ -11,7 +11,7 @@ module Domains preclean_pendings clean_pendings! - domain.save! + domain.save(validate: false) end end end diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index f01e7c41e..38aaa5339 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -64,4 +64,24 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE end + + def test_clears_pending_update_and_inactive_after_denial + epp_xml = "\n\n \n \n \n #{@domain.name}\n" \ + " \n #{@new_registrant.code}\n \n \n \n \n \n" \ + " \n #{@legal_doc_path}\n \n" \ + " \n 20alla-1594199756\n \n\n" + @domain.pending_json['frame'] = epp_xml + @domain.update(pending_json: @domain.pending_json) + @domain.update(statuses: [DomainStatus::INACTIVE, DomainStatus::PENDING_UPDATE]) + @domain.nameservers.destroy_all + @domain.reload + + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) + @domain.reload + + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + assert_not @domain.statuses.include? DomainStatus::PENDING_UPDATE + assert @domain.statuses.include? DomainStatus::INACTIVE + end end From 252d39464af5f299d2a9ad1fa101a4564ac67659 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 3 Dec 2020 13:39:58 +0500 Subject: [PATCH 053/106] Fix updating procedure --- .../domains/update_confirm/base.rb | 2 ++ .../update_confirm/process_update_confirmed.rb | 2 -- .../update_confirm/process_update_rejected.rb | 1 - test/jobs/domain_update_confirm_job_test.rb | 18 ++++++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/interactions/domains/update_confirm/base.rb b/app/interactions/domains/update_confirm/base.rb index ab5584c03..0e1fa81d3 100644 --- a/app/interactions/domains/update_confirm/base.rb +++ b/app/interactions/domains/update_confirm/base.rb @@ -33,10 +33,12 @@ module Domains 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 diff --git a/app/interactions/domains/update_confirm/process_update_confirmed.rb b/app/interactions/domains/update_confirm/process_update_confirmed.rb index a4ceb1d3e..cb69d042e 100644 --- a/app/interactions/domains/update_confirm/process_update_confirmed.rb +++ b/app/interactions/domains/update_confirm/process_update_confirmed.rb @@ -3,7 +3,6 @@ module Domains class ProcessUpdateConfirmed < Base def execute ActiveRecord::Base.transaction do - domain.is_admin = true old_registrant = domain.registrant notify_registrar(:poll_pending_update_confirmed_by_registrant) @@ -17,7 +16,6 @@ module Domains preclean_pendings update_domain clean_pendings! - domain.save(validate: false) WhoisRecord.find_by(domain_id: domain.id).save # need to reload model end diff --git a/app/interactions/domains/update_confirm/process_update_rejected.rb b/app/interactions/domains/update_confirm/process_update_rejected.rb index 5ce818e66..1d7b75b0e 100644 --- a/app/interactions/domains/update_confirm/process_update_rejected.rb +++ b/app/interactions/domains/update_confirm/process_update_rejected.rb @@ -11,7 +11,6 @@ module Domains preclean_pendings clean_pendings! - domain.save(validate: false) end end end diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index 38aaa5339..afffae157 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -84,4 +84,22 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase assert_not @domain.statuses.include? DomainStatus::PENDING_UPDATE assert @domain.statuses.include? DomainStatus::INACTIVE end + + def test_clears_pending_update_and_sets_ok_after_denial + epp_xml = "\n\n \n \n \n #{@domain.name}\n" \ + " \n #{@new_registrant.code}\n \n \n \n \n \n" \ + " \n #{@legal_doc_path}\n \n" \ + " \n 20alla-1594199756\n \n\n" + @domain.pending_json['frame'] = epp_xml + @domain.update(pending_json: @domain.pending_json) + @domain.update(statuses: [DomainStatus::OK, DomainStatus::PENDING_UPDATE]) + + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) + @domain.reload + + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + assert_not @domain.statuses.include? DomainStatus::PENDING_UPDATE + assert @domain.statuses.include? DomainStatus::OK + end end From 7a90ef528abb14d0df62b956b6738a26d3593c5e Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 4 Dec 2020 13:57:53 +0500 Subject: [PATCH 054/106] Add a couple of domain status tests --- test/jobs/domain_update_confirm_job_test.rb | 39 ++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index afffae157..ded0d3d8a 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -48,6 +48,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase @domain.reload assert_equal @domain.registrant.code, @new_registrant.code + assert @domain.statuses.include? DomainStatus::OK end def test_clears_pending_update_after_denial @@ -65,6 +66,42 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE end + def test_protects_statuses_after_denial + epp_xml = "\n\n \n \n \n #{@domain.name}\n" \ + " \n #{@new_registrant.code}\n \n \n \n \n \n" \ + " \n #{@legal_doc_path}\n \n" \ + " \n 20alla-1594199756\n \n\n" + @domain.pending_json['frame'] = epp_xml + @domain.update(pending_json: @domain.pending_json) + @domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED]) + + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) + @domain.reload + + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + assert @domain.statuses.include? DomainStatus::DELETE_CANDIDATE + assert @domain.statuses.include? DomainStatus::DISPUTED + end + + def test_protects_statuses_after_confirm + epp_xml = "\n\n \n \n \n #{@domain.name}\n" \ + " \n #{@new_registrant.code}\n \n \n \n \n \n" \ + " \n #{@legal_doc_path}\n \n" \ + " \n 20alla-1594199756\n \n\n" + @domain.pending_json['frame'] = epp_xml + @domain.update(pending_json: @domain.pending_json) + @domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED]) + + DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::CONFIRMED) + @domain.reload + + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + assert @domain.statuses.include? DomainStatus::DELETE_CANDIDATE + assert @domain.statuses.include? DomainStatus::DISPUTED + end + def test_clears_pending_update_and_inactive_after_denial epp_xml = "\n\n \n \n \n #{@domain.name}\n" \ " \n #{@new_registrant.code}\n \n \n \n \n \n" \ @@ -72,7 +109,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase " \n 20alla-1594199756\n \n\n" @domain.pending_json['frame'] = epp_xml @domain.update(pending_json: @domain.pending_json) - @domain.update(statuses: [DomainStatus::INACTIVE, DomainStatus::PENDING_UPDATE]) + @domain.update(statuses: [DomainStatus::PENDING_UPDATE]) @domain.nameservers.destroy_all @domain.reload From e8fa79304f7e1b34846d74989deac1d753b6bbf7 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 1 Dec 2020 15:23:23 +0500 Subject: [PATCH 055/106] Move DomainCron#clean_expired_pendings to interactor --- .../domains/expired_pendings/base.rb | 10 ++++ .../domains/expired_pendings/clean_all.rb | 35 +++++++++++ .../domains/expired_pendings/process_clean.rb | 60 +++++++++++++++++++ app/models/domain_cron.rb | 32 +--------- test/models/domain_cron_test.rb | 8 ++- 5 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 app/interactions/domains/expired_pendings/base.rb create mode 100644 app/interactions/domains/expired_pendings/clean_all.rb create mode 100644 app/interactions/domains/expired_pendings/process_clean.rb diff --git a/app/interactions/domains/expired_pendings/base.rb b/app/interactions/domains/expired_pendings/base.rb new file mode 100644 index 000000000..7faa32050 --- /dev/null +++ b/app/interactions/domains/expired_pendings/base.rb @@ -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 diff --git a/app/interactions/domains/expired_pendings/clean_all.rb b/app/interactions/domains/expired_pendings/clean_all.rb new file mode 100644 index 000000000..1dbab266c --- /dev/null +++ b/app/interactions/domains/expired_pendings/clean_all.rb @@ -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 diff --git a/app/interactions/domains/expired_pendings/process_clean.rb b/app/interactions/domains/expired_pendings/process_clean.rb new file mode 100644 index 000000000..c6277c3c5 --- /dev/null +++ b/app/interactions/domains/expired_pendings/process_clean.rb @@ -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 diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index d09141d52..77de7062a 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -1,36 +1,6 @@ class DomainCron 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 diff --git a/test/models/domain_cron_test.rb b/test/models/domain_cron_test.rb index 0224b1a61..c417df04f 100644 --- a/test/models/domain_cron_test.rb +++ b/test/models/domain_cron_test.rb @@ -19,7 +19,9 @@ class DomainCronTest < ActiveSupport::TestCase registrant_verification_token: 'test', statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION]) - DomainCron.clean_expired_pendings + perform_enqueued_jobs do + DomainCron.clean_expired_pendings + end assert_emails 1 end @@ -84,7 +86,9 @@ class DomainCronTest < ActiveSupport::TestCase assert @domain.pending_update? @domain.reload - DomainCron.clean_expired_pendings + perform_enqueued_jobs do + DomainCron.clean_expired_pendings + end @domain.reload assert_not @domain.pending_update? From 849010b118addcba6057caef1d2b7685e2568fef Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 1 Dec 2020 16:44:31 +0500 Subject: [PATCH 056/106] Move #process_expired to interactor --- .../domains/expire_period/base.rb | 10 +++++++ .../domains/expire_period/process_expired.rb | 28 +++++++++++++++++++ .../domains/expire_period/start.rb | 19 +++++++++++++ app/models/domain.rb | 6 ---- app/models/domain_cron.rb | 22 +-------------- 5 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 app/interactions/domains/expire_period/base.rb create mode 100644 app/interactions/domains/expire_period/process_expired.rb create mode 100644 app/interactions/domains/expire_period/start.rb diff --git a/app/interactions/domains/expire_period/base.rb b/app/interactions/domains/expire_period/base.rb new file mode 100644 index 000000000..eab8171bf --- /dev/null +++ b/app/interactions/domains/expire_period/base.rb @@ -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 diff --git a/app/interactions/domains/expire_period/process_expired.rb b/app/interactions/domains/expire_period/process_expired.rb new file mode 100644 index 000000000..595de1228 --- /dev/null +++ b/app/interactions/domains/expire_period/process_expired.rb @@ -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 diff --git a/app/interactions/domains/expire_period/start.rb b/app/interactions/domains/expire_period/start.rb new file mode 100644 index 000000000..1ed2342f1 --- /dev/null +++ b/app/interactions/domains/expire_period/start.rb @@ -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 diff --git a/app/models/domain.rb b/app/models/domain.rb index dc7d86da8..33d2dcd58 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -482,12 +482,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 diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index 77de7062a..cd063f901 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -4,27 +4,7 @@ class DomainCron 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 From d17e26c28b81e7ea9dc75d1fecd19ed14df1f623 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 1 Dec 2020 17:04:19 +0500 Subject: [PATCH 057/106] Move #redemption_grace_period to interactor --- .../domains/redemption_grace_period/base.rb | 10 ++++++++++ .../process_grace_period.rb | 20 +++++++++++++++++++ .../domains/redemption_grace_period/start.rb | 20 +++++++++++++++++++ app/models/domain_cron.rb | 19 +----------------- 4 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 app/interactions/domains/redemption_grace_period/base.rb create mode 100644 app/interactions/domains/redemption_grace_period/process_grace_period.rb create mode 100644 app/interactions/domains/redemption_grace_period/start.rb diff --git a/app/interactions/domains/redemption_grace_period/base.rb b/app/interactions/domains/redemption_grace_period/base.rb new file mode 100644 index 000000000..5d1ede289 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/base.rb @@ -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 diff --git a/app/interactions/domains/redemption_grace_period/process_grace_period.rb b/app/interactions/domains/redemption_grace_period/process_grace_period.rb new file mode 100644 index 000000000..0f120a996 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/process_grace_period.rb @@ -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 diff --git a/app/interactions/domains/redemption_grace_period/start.rb b/app/interactions/domains/redemption_grace_period/start.rb new file mode 100644 index 000000000..ef7f42e58 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/start.rb @@ -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 diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index cd063f901..e936c29e6 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -8,24 +8,7 @@ class DomainCron end def self.start_redemption_grace_period - STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test? - - ::PaperTrail.request.whodunnit = "cron - #{__method__}" - - domains = Domain.outzone_candidates - marked = 0 - real = 0 - - domains.each do |domain| - next unless domain.server_holdable? - real += 1 - domain.statuses << DomainStatus::SERVER_HOLD - STDOUT << "#{Time.zone.now.utc} DomainCron.start_redemption_grace_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - domain.save(validate: false) and marked += 1 - end - - STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{marked} of #{real} domains\n" unless Rails.env.test? - marked + Domains::RedemptionGracePeriod::Start.run! end def self.start_client_hold From 167b37c61fb4aefae70cbf7e3c1c281322f094ba Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 2 Dec 2020 14:31:37 +0500 Subject: [PATCH 058/106] Add tests for DOmainCrone#expire_period --- test/interactions/expire_period/start_test.rb | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/interactions/expire_period/start_test.rb diff --git a/test/interactions/expire_period/start_test.rb b/test/interactions/expire_period/start_test.rb new file mode 100644 index 000000000..168b255bb --- /dev/null +++ b/test/interactions/expire_period/start_test.rb @@ -0,0 +1,28 @@ +require 'test_helper' + +class StartTest < ActiveSupport::TestCase + include ActionMailer::TestHelper + + setup do + @domain = domains(:shop) + @domain.update(expire_time: Time.zone.now - 1.day) + ActionMailer::Base.deliveries.clear + end + + def test_sets_expired + job_count = lambda do + QueJob.where("args->>0 = '#{@domain.id}'", job_class: DomainExpireEmailJob.name).count + end + + assert_difference job_count, 1 do + perform_enqueued_jobs do + DomainCron.start_expire_period + end + end + + @domain.reload + assert @domain.statuses.include?(DomainStatus::EXPIRED) + assert_equal @domain.outzone_at, @domain.expire_time + Domain.expire_warning_period + assert_equal @domain.delete_date, (@domain.outzone_at + Domain.redemption_grace_period).to_date + end +end From ac3860bbd8fc66b7eaa7ba2254516a0482642bad Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 2 Dec 2020 14:54:37 +0500 Subject: [PATCH 059/106] Add test for redemption grace period --- .../redemption_grace_period/start_test.rb | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 test/interactions/redemption_grace_period/start_test.rb diff --git a/test/interactions/redemption_grace_period/start_test.rb b/test/interactions/redemption_grace_period/start_test.rb new file mode 100644 index 000000000..8958030f0 --- /dev/null +++ b/test/interactions/redemption_grace_period/start_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +class StartTest < ActiveSupport::TestCase + + setup do + @domain = domains(:shop) + @domain.update(outzone_time: Time.zone.now - 1.day) + end + + def test_sets_server_hold + DomainCron.start_redemption_grace_period + + @domain.reload + assert @domain.statuses.include?(DomainStatus::SERVER_HOLD) + end + + def test_doesnt_sets_server_hold_if_not_outzone + @domain.update(outzone_time: nil) + @domain.reload + DomainCron.start_redemption_grace_period + + @domain.reload + assert_not @domain.statuses.include?(DomainStatus::SERVER_HOLD) + end +end From ccf91d306abdadced826e6afb09d6b60dbfa9e5f Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 4 Dec 2020 17:48:42 +0500 Subject: [PATCH 060/106] Rename email sending interactor --- .../{delete_confirm => delete_confirm_email}/send_request.rb | 2 +- app/models/domain.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/interactions/domains/{delete_confirm => delete_confirm_email}/send_request.rb (96%) diff --git a/app/interactions/domains/delete_confirm/send_request.rb b/app/interactions/domains/delete_confirm_email/send_request.rb similarity index 96% rename from app/interactions/domains/delete_confirm/send_request.rb rename to app/interactions/domains/delete_confirm_email/send_request.rb index 91afaefb8..7070423a6 100644 --- a/app/interactions/domains/delete_confirm/send_request.rb +++ b/app/interactions/domains/delete_confirm_email/send_request.rb @@ -1,5 +1,5 @@ module Domains - module DeleteConfirm + module DeleteConfirmEmail class SendRequest < ActiveInteraction::Base object :domain, class: Domain, diff --git a/app/models/domain.rb b/app/models/domain.rb index dc7d86da8..ee3481bb2 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -418,7 +418,7 @@ class Domain < ApplicationRecord pending_delete_confirmation! save(validate: false) # should check if this did succeed - Domains::DeleteConfirm::SendRequest.run(domain: self) + Domains::DeleteConfirmEmail::SendRequest.run(domain: self) end def cancel_pending_delete From f6a7a08b2433b20b1c131f7bc307b52a9e98b580 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Fri, 4 Dec 2020 18:09:11 +0500 Subject: [PATCH 061/106] Move job to interactor --- .../domains/delete_confirm/base.rb | 23 ++++++++++ .../domains/delete_confirm/process_action.rb | 17 ++++++++ .../process_delete_confirmed.rb | 11 +++++ .../delete_confirm/process_delete_rejected.rb | 34 +++++++++++++++ app/jobs/application_job.rb | 2 + app/jobs/domain_delete_confirm_job.rb | 42 ++++--------------- app/models/registrant_verification.rb | 4 +- test/jobs/domain_delete_confirm_job_test.rb | 8 ++-- .../domains/domain_delete_confirms_test.rb | 9 +++- 9 files changed, 107 insertions(+), 43 deletions(-) create mode 100644 app/interactions/domains/delete_confirm/base.rb create mode 100644 app/interactions/domains/delete_confirm/process_action.rb create mode 100644 app/interactions/domains/delete_confirm/process_delete_confirmed.rb create mode 100644 app/interactions/domains/delete_confirm/process_delete_rejected.rb create mode 100644 app/jobs/application_job.rb diff --git a/app/interactions/domains/delete_confirm/base.rb b/app/interactions/domains/delete_confirm/base.rb new file mode 100644 index 000000000..d1d45f006 --- /dev/null +++ b/app/interactions/domains/delete_confirm/base.rb @@ -0,0 +1,23 @@ +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 + end + end +end diff --git a/app/interactions/domains/delete_confirm/process_action.rb b/app/interactions/domains/delete_confirm/process_action.rb new file mode 100644 index 000000000..59f23de67 --- /dev/null +++ b/app/interactions/domains/delete_confirm/process_action.rb @@ -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 diff --git a/app/interactions/domains/delete_confirm/process_delete_confirmed.rb b/app/interactions/domains/delete_confirm/process_delete_confirmed.rb new file mode 100644 index 000000000..553809666 --- /dev/null +++ b/app/interactions/domains/delete_confirm/process_delete_confirmed.rb @@ -0,0 +1,11 @@ +module Domains + module DeleteConfirm + class ProcessDeleteConfirmed < Base + def execute + domain.notify_registrar(:poll_pending_delete_confirmed_by_registrant) + domain.apply_pending_delete! + raise_errors!(domain) + end + end + end +end diff --git a/app/interactions/domains/delete_confirm/process_delete_rejected.rb b/app/interactions/domains/delete_confirm/process_delete_rejected.rb new file mode 100644 index 000000000..5038ba150 --- /dev/null +++ b/app/interactions/domains/delete_confirm/process_delete_rejected.rb @@ -0,0 +1,34 @@ +module Domains + module DeleteConfirm + class ProcessDeleteRejected < Base + def execute + 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) + + send_domain_deleted_email + end + + def send_domain_deleted_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 diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 000000000..a009ace51 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/jobs/domain_delete_confirm_job.rb b/app/jobs/domain_delete_confirm_job.rb index e94f2432c..afea3da59 100644 --- a/app/jobs/domain_delete_confirm_job.rb +++ b/app/jobs/domain_delete_confirm_job.rb @@ -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 diff --git a/app/models/registrant_verification.rb b/app/models/registrant_verification.rb index 097f0cfa9..f0c9f3b97 100644 --- a/app/models/registrant_verification.rb +++ b/app/models/registrant_verification.rb @@ -30,12 +30,12 @@ class RegistrantVerification < ApplicationRecord 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 diff --git a/test/jobs/domain_delete_confirm_job_test.rb b/test/jobs/domain_delete_confirm_job_test.rb index b999bd3c7..cbe4b87f1 100644 --- a/test/jobs/domain_delete_confirm_job_test.rb +++ b/test/jobs/domain_delete_confirm_job_test.rb @@ -18,7 +18,7 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase new_registrant_email: @new_registrant.email, current_user_id: @user.id }) - DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) + DomainDeleteConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) last_registrar_notification = @domain.registrar.notifications.last assert_equal(last_registrar_notification.attached_obj_id, @domain.id) @@ -31,7 +31,7 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase new_registrant_email: @new_registrant.email, current_user_id: @user.id }) - DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) + DomainDeleteConfirmJob.perform_now(@domain.id, RegistrantVerification::CONFIRMED) last_registrar_notification = @domain.registrar.notifications.last assert_equal(last_registrar_notification.attached_obj_id, @domain.id) @@ -51,7 +51,7 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase assert @domain.registrant_delete_confirmable?(@domain.registrant_verification_token) assert_equal @user.id, @domain.pending_json['current_user_id'] - DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) + DomainDeleteConfirmJob.perform_now(@domain.id, RegistrantVerification::CONFIRMED) @domain.reload assert @domain.statuses.include? DomainStatus::PENDING_DELETE @@ -72,7 +72,7 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase assert @domain.registrant_delete_confirmable?(@domain.registrant_verification_token) assert_equal @user.id, @domain.pending_json['current_user_id'] - DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) + DomainDeleteConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED) @domain.reload assert_equal ['ok'], @domain.statuses diff --git a/test/system/registrant_area/domains/domain_delete_confirms_test.rb b/test/system/registrant_area/domains/domain_delete_confirms_test.rb index 0eb61ada8..765cd0149 100644 --- a/test/system/registrant_area/domains/domain_delete_confirms_test.rb +++ b/test/system/registrant_area/domains/domain_delete_confirms_test.rb @@ -1,6 +1,7 @@ require 'application_system_test_case' class DomainDeleteConfirmsTest < ApplicationSystemTestCase + include ActionMailer::TestHelper setup do @user = users(:registrant) sign_in @user @@ -13,7 +14,9 @@ class DomainDeleteConfirmsTest < ApplicationSystemTestCase def test_enqueues_approve_job_after_verification visit registrant_domain_delete_confirm_url(@domain.id, token: @domain.registrant_verification_token) - click_on 'Confirm domain delete' + perform_enqueued_jobs do + click_on 'Confirm domain delete' + end assert_text 'Domain registrant change has successfully received.' @domain.reload @@ -23,7 +26,9 @@ class DomainDeleteConfirmsTest < ApplicationSystemTestCase def test_enqueues_reject_job_after_verification visit registrant_domain_delete_confirm_url(@domain.id, token: @domain.registrant_verification_token) - click_on 'Reject domain delete' + perform_enqueued_jobs do + click_on 'Reject domain delete' + end assert_text 'Domain registrant change has been rejected successfully.' @domain.reload From 5a059e86bb9bf380e610350adf705062276d726a Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 7 Dec 2020 17:08:54 +0500 Subject: [PATCH 062/106] Move confirmed delete procedures to interactor --- .../domains/delete_confirm/base.rb | 30 ++++++++++++++ .../process_delete_confirmed.rb | 41 ++++++++++++++++++- .../delete_confirm/process_delete_rejected.rb | 4 +- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/app/interactions/domains/delete_confirm/base.rb b/app/interactions/domains/delete_confirm/base.rb index d1d45f006..5bd07f40f 100644 --- a/app/interactions/domains/delete_confirm/base.rb +++ b/app/interactions/domains/delete_confirm/base.rb @@ -18,6 +18,36 @@ module Domains 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 diff --git a/app/interactions/domains/delete_confirm/process_delete_confirmed.rb b/app/interactions/domains/delete_confirm/process_delete_confirmed.rb index 553809666..1f3068107 100644 --- a/app/interactions/domains/delete_confirm/process_delete_confirmed.rb +++ b/app/interactions/domains/delete_confirm/process_delete_confirmed.rb @@ -2,10 +2,49 @@ module Domains module DeleteConfirm class ProcessDeleteConfirmed < Base def execute - domain.notify_registrar(:poll_pending_delete_confirmed_by_registrant) + 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 diff --git a/app/interactions/domains/delete_confirm/process_delete_rejected.rb b/app/interactions/domains/delete_confirm/process_delete_rejected.rb index 5038ba150..1844801ac 100644 --- a/app/interactions/domains/delete_confirm/process_delete_rejected.rb +++ b/app/interactions/domains/delete_confirm/process_delete_rejected.rb @@ -9,10 +9,10 @@ module Domains domain.save(validate: false) raise_errors!(domain) - send_domain_deleted_email + send_domain_delete_rejected_email end - def send_domain_deleted_email + 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? From ce07c5eae83c27f0043d98ad58a99bdb9bbc5dd4 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Mon, 7 Dec 2020 17:37:44 +0500 Subject: [PATCH 063/106] Move rejected delete procedures to interactor --- .../domains/delete_confirm/process_delete_rejected.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/interactions/domains/delete_confirm/process_delete_rejected.rb b/app/interactions/domains/delete_confirm/process_delete_rejected.rb index 1844801ac..25b491660 100644 --- a/app/interactions/domains/delete_confirm/process_delete_rejected.rb +++ b/app/interactions/domains/delete_confirm/process_delete_rejected.rb @@ -2,10 +2,8 @@ module Domains module DeleteConfirm class ProcessDeleteRejected < Base def execute - domain.statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION) - domain.notify_registrar(:poll_pending_delete_rejected_by_registrant) - domain.cancel_pending_delete + notify_registrar(:poll_pending_delete_rejected_by_registrant) domain.save(validate: false) raise_errors!(domain) From 6841703349339614256601367f7d352a286d8a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 8 Dec 2020 10:35:25 +0200 Subject: [PATCH 064/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9774d5cb3..6dd2e66dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +08.12.2020 +* Replaced Travis-CI with GitHub Actions [#1746](https://github.com/internetee/registry/pull/1746) + 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) From a54249f6ff7ecaddab9d9b6c7e7e174c59db5f25 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 8 Dec 2020 16:08:33 +0500 Subject: [PATCH 065/106] Move WhoisUpdate job to interactor --- app/interactions/whois/delete_record.rb | 48 ++++++++++++++ app/interactions/whois/update.rb | 39 ++++++++++++ app/interactions/whois/update_record.rb | 32 ++++++++++ app/jobs/update_whois_record_job.rb | 84 +------------------------ 4 files changed, 120 insertions(+), 83 deletions(-) create mode 100644 app/interactions/whois/delete_record.rb create mode 100644 app/interactions/whois/update.rb create mode 100644 app/interactions/whois/update_record.rb diff --git a/app/interactions/whois/delete_record.rb b/app/interactions/whois/delete_record.rb new file mode 100644 index 000000000..62e416d2f --- /dev/null +++ b/app/interactions/whois/delete_record.rb @@ -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 diff --git a/app/interactions/whois/update.rb b/app/interactions/whois/update.rb new file mode 100644 index 000000000..bd37b4576 --- /dev/null +++ b/app/interactions/whois/update.rb @@ -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 diff --git a/app/interactions/whois/update_record.rb b/app/interactions/whois/update_record.rb new file mode 100644 index 000000000..6fc838968 --- /dev/null +++ b/app/interactions/whois/update_record.rb @@ -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 diff --git a/app/jobs/update_whois_record_job.rb b/app/jobs/update_whois_record_job.rb index 2973d5a6b..d067807a0 100644 --- a/app/jobs/update_whois_record_job.rb +++ b/app/jobs/update_whois_record_job.rb @@ -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 From 8f6f2433e24cd0f3918c786223abd63d8e38b017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 8 Dec 2020 18:17:10 +0200 Subject: [PATCH 066/106] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dd2e66dd..5e823c7b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 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) From 7573a7eac2e1dd7a5540855a491f367dec8113e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 9 Dec 2020 16:33:23 +0200 Subject: [PATCH 067/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e823c7b1..7300adbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From de37732a56abf42c06b165e208c01c03d91a22e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Mon, 14 Dec 2020 15:21:04 +0200 Subject: [PATCH 068/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7300adbdb..60d7c1e24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From ee2601b8de655359c7de3472cd8ce252ddcab119 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 9 Dec 2020 16:50:53 +0500 Subject: [PATCH 069/106] Add scaffold for a controller & view --- Gemfile | 1 + Gemfile.lock | 7 ++++++ .../registrar/bulk_renew_controller.rb | 9 ++++++++ .../bulk_change/_api_errors.html.erb | 9 ++++++++ .../bulk_change/_bulk_renew_form.html.erb | 22 +++++++++++++++++++ app/views/registrar/bulk_change/new.html.erb | 8 +++++++ config/locales/registrar/bulk_change.en.yml | 5 +++++ config/routes.rb | 2 ++ 8 files changed, 63 insertions(+) create mode 100644 app/controllers/registrar/bulk_renew_controller.rb create mode 100644 app/views/registrar/bulk_change/_api_errors.html.erb create mode 100644 app/views/registrar/bulk_change/_bulk_renew_form.html.erb diff --git a/Gemfile b/Gemfile index 9bbcba254..9aad8b7ae 100644 --- a/Gemfile +++ b/Gemfile @@ -80,6 +80,7 @@ gem 'directo', github: 'internetee/directo', branch: 'master' group :development, :test do + gem 'listen' gem 'pry', '0.10.1' gem 'puma' end diff --git a/Gemfile.lock b/Gemfile.lock index 2a0bb55b1..3c9da920e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -250,6 +250,9 @@ GEM kaminari-core (= 1.2.1) kaminari-core (1.2.1) libxml-ruby (3.2.0) + listen (3.3.3) + 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) @@ -363,6 +366,9 @@ 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) @@ -510,6 +516,7 @@ DEPENDENCIES jquery-ui-rails (= 5.0.5) kaminari lhv! + listen minitest (~> 5.14) money-rails nokogiri diff --git a/app/controllers/registrar/bulk_renew_controller.rb b/app/controllers/registrar/bulk_renew_controller.rb new file mode 100644 index 000000000..8818e416c --- /dev/null +++ b/app/controllers/registrar/bulk_renew_controller.rb @@ -0,0 +1,9 @@ +class Registrar + class BulkRenewController < DeppController + def index; end + + def new + authorize! :manage, :repp + end + end +end diff --git a/app/views/registrar/bulk_change/_api_errors.html.erb b/app/views/registrar/bulk_change/_api_errors.html.erb new file mode 100644 index 000000000..56bf8c404 --- /dev/null +++ b/app/views/registrar/bulk_change/_api_errors.html.erb @@ -0,0 +1,9 @@ +<% if @api_errors %> +
+
    + <% @api_errors.each do |error| %> +
  • <%= error[:title] %>
  • + <% end %> +
+
+<% end %> diff --git a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb new file mode 100644 index 000000000..38134e707 --- /dev/null +++ b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb @@ -0,0 +1,22 @@ +<%= form_tag registrar_new_registrar_bulk_renew_path, multipart: true, class: 'form-horizontal' do %> + <%= render 'api_errors' %> + + +
+
+ <%= label_tag 'expire_date', t('.expire_date') %> +
+
+ <%= text_field :expire_date, params[:expire_date], + class: 'form-control js-datepicker' %> +
+
+ +
+
+ +
+
+<% end %> diff --git a/app/views/registrar/bulk_change/new.html.erb b/app/views/registrar/bulk_change/new.html.erb index da85899ff..e61270b6d 100644 --- a/app/views/registrar/bulk_change/new.html.erb +++ b/app/views/registrar/bulk_change/new.html.erb @@ -19,6 +19,10 @@
  • <%= t '.bulk_transfer' %>
  • + +
  • + <%= t '.bulk_renew' %> +
  • @@ -34,4 +38,8 @@
    <%= render 'bulk_transfer_form' %>
    + +
    + <%= render 'bulk_renew_form' %> +
    diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index 7c1f11da9..d9f932a46 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -6,6 +6,7 @@ en: technical_contact: Technical contact nameserver: Nameserver bulk_transfer: Bulk transfer + bulk_renew: Bulk renew tech_contact_form: current_contact_id: Current contact ID @@ -29,3 +30,7 @@ en: submit_btn: Transfer help_btn: Toggle help help: Transfer domains in the csv file with correct transfer code to this registrar + + bulk_renew_form: + filter_btn: Filter + expire_date: Expire date diff --git a/config/routes.rb b/config/routes.rb index 0af3d95c9..2a6930d3f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,6 +133,8 @@ Rails.application.routes.draw do end resources :domain_transfers, only: %i[new create] resource :bulk_change, controller: :bulk_change, only: :new + # resource :bulk_renew, controller: :bulk_renew #, only: :index + post '/registrar/bulk_renew/new', to: 'bulk_renew#new', as: :new_registrar_bulk_renew resource :tech_contacts, only: :update resource :nameservers, only: :update resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do From 9c662471a71671c76a1041a22fba12766f04fdea Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 10 Dec 2020 14:07:07 +0500 Subject: [PATCH 070/106] Fix controller & routes --- app/controllers/registrar/bulk_change_controller.rb | 7 +++++++ app/controllers/registrar/bulk_renew_controller.rb | 9 --------- .../registrar/bulk_change/_bulk_renew_form.html.erb | 8 ++++---- config/locales/registrar/bulk_change.en.yml | 2 +- config/routes.rb | 3 +-- 5 files changed, 13 insertions(+), 16 deletions(-) delete mode 100644 app/controllers/registrar/bulk_renew_controller.rb diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 441127f6c..1d9d606a4 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -4,9 +4,16 @@ 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 + @expire_date = params[:expire_date].to_date + render file: 'registrar/bulk_change/new', locals: { active_tab: :bulk_renew } + end + private def available_contacts diff --git a/app/controllers/registrar/bulk_renew_controller.rb b/app/controllers/registrar/bulk_renew_controller.rb deleted file mode 100644 index 8818e416c..000000000 --- a/app/controllers/registrar/bulk_renew_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Registrar - class BulkRenewController < DeppController - def index; end - - def new - authorize! :manage, :repp - end - end -end diff --git a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb index 38134e707..4b7cd392b 100644 --- a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb +++ b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb @@ -1,14 +1,14 @@ -<%= form_tag registrar_new_registrar_bulk_renew_path, multipart: true, class: 'form-horizontal' do %> +<%= form_with url: registrar_bulk_renew_path, multipart: true, class: 'form-horizontal' do |f|%> <%= render 'api_errors' %>
    - <%= label_tag 'expire_date', t('.expire_date') %> + <%= f.label :expire_date, t('.expire_date') %>
    - <%= text_field :expire_date, params[:expire_date], - class: 'form-control js-datepicker' %> + <%= f.text_field :expire_date, value: @expire_date, + class: 'form-control js-datepicker'%>
    diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index d9f932a46..51e6a8bb3 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -33,4 +33,4 @@ en: bulk_renew_form: filter_btn: Filter - expire_date: Expire date + expire_date: Expire date until diff --git a/config/routes.rb b/config/routes.rb index 2a6930d3f..7bf1ecd39 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,8 +133,7 @@ Rails.application.routes.draw do end resources :domain_transfers, only: %i[new create] resource :bulk_change, controller: :bulk_change, only: :new - # resource :bulk_renew, controller: :bulk_renew #, only: :index - post '/registrar/bulk_renew/new', to: 'bulk_renew#new', as: :new_registrar_bulk_renew + post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew resource :tech_contacts, only: :update resource :nameservers, only: :update resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do From 40b22cd433b645c25567c27e440fce93226ba958 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Thu, 10 Dec 2020 14:35:04 +0500 Subject: [PATCH 071/106] Add multiple checkboxes to select domains for bulk renew --- .../registrar/bulk_change_controller.rb | 10 ++++++++++ .../bulk_change/_bulk_renew_form.html.erb | 17 +++++++++++++++++ config/locales/registrar/bulk_change.en.yml | 1 + 3 files changed, 28 insertions(+) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 1d9d606a4..358a1949c 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -11,6 +11,8 @@ class Registrar def bulk_renew authorize! :manage, :repp @expire_date = params[:expire_date].to_date + # binding.pry + @domains = domains_by_date(@expire_date) render file: 'registrar/bulk_change/new', locals: { active_tab: :bulk_renew } end @@ -23,5 +25,13 @@ 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 end end diff --git a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb index 4b7cd392b..874dc8eaa 100644 --- a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb +++ b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb @@ -12,6 +12,23 @@
    + <% if @domains.present? %> +
    +
    + <%= f.label :domain_ids, t('.domain_ids') %> +
    +
    + <%= f.collection_check_boxes :domain_ids, @domains, :id, :name, + checked: @domains.map(&:id) do |b|%> +
    + <%= b.check_box %> + <%= b.label %> +
    + <% end %> +
    +
    + <% end %> +
    -
    +
    + <%= f.submit "#{t '.filter_btn'}", name: 'filter', class: 'btn btn-warning' %> + <% if @domains.present? %> + <%= f.submit "#{t '.renew_btn'}", name: 'renew', class: 'btn btn-primary' %> + <% end %>
    <% end %> diff --git a/config/locales/registrar/bulk_change.en.yml b/config/locales/registrar/bulk_change.en.yml index 5043a3f94..75becfada 100644 --- a/config/locales/registrar/bulk_change.en.yml +++ b/config/locales/registrar/bulk_change.en.yml @@ -33,6 +33,7 @@ en: bulk_renew_form: filter_btn: Filter + renew_btn: Renew expire_date: Expire date until domain_ids: Domains for bulk renewal current_balance: Current balance diff --git a/test/system/registrar_area/bulk_change/bulk_renew_test.rb b/test/system/registrar_area/bulk_change/bulk_renew_test.rb index c99750e6c..bcb6c3d66 100644 --- a/test/system/registrar_area/bulk_change/bulk_renew_test.rb +++ b/test/system/registrar_area/bulk_change/bulk_renew_test.rb @@ -30,11 +30,9 @@ class BulkRenewTest < ApplicationSystemTestCase visit new_registrar_bulk_change_url click_link('Bulk renew') - select '1 year', from: 'Period' click_button 'Filter' - - click_button 'Filter' + click_button 'Renew' assert_text 'invalid.test' assert_no_text 'shop.test' From 95a789ab600def6a3bef10d77f6119643c0cf190 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 15 Dec 2020 13:54:47 +0500 Subject: [PATCH 083/106] Add better error handling for single domain renewal tasks --- .../domains/bulk_renew/single_domain_renew.rb | 13 +++++++--- app/interactions/domains/bulk_renew/start.rb | 25 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/interactions/domains/bulk_renew/single_domain_renew.rb b/app/interactions/domains/bulk_renew/single_domain_renew.rb index fa6d3a7ae..66c6244b3 100644 --- a/app/interactions/domains/bulk_renew/single_domain_renew.rb +++ b/app/interactions/domains/bulk_renew/single_domain_renew.rb @@ -10,12 +10,11 @@ module Domains def execute in_transaction_with_retries do success = domain.renew(domain.valid_to, period, unit) - if success check_balance reduce_balance else - errors.add(:domain, I18n.t('domain_renew_error_for_domain', domain: domain.name)) + add_error end end end @@ -36,11 +35,11 @@ module Domains price: domain_pricelist) end - def in_transaction_with_retries(&block) + def in_transaction_with_retries if Rails.env.test? yield else - transaction_wrapper(block) + transaction_wrapper { yield } end rescue ActiveRecord::StatementInvalid sleep rand / 100 @@ -52,6 +51,12 @@ module Domains 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 diff --git a/app/interactions/domains/bulk_renew/start.rb b/app/interactions/domains/bulk_renew/start.rb index abd36bb76..d407afade 100644 --- a/app/interactions/domains/bulk_renew/start.rb +++ b/app/interactions/domains/bulk_renew/start.rb @@ -8,20 +8,22 @@ module Domains object :registrar def execute - if mass_check_balance.valid? && mass_check_balance.result + if renewable? domains.each do |domain| - Domains::BulkRenew::SingleDomainRenew.run(domain: domain, - period: period, - unit: unit, - registrar: registrar) + task = run_task(domain) + manage_errors(task) end else - errors.merge!(mass_check_balance.errors) + 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 @@ -37,6 +39,17 @@ module Domains unit: unit, balance: registrar.balance) end + + def manage_errors(task) + errors.merge!(task.errors) unless task.valid? + end + + def run_task(domain) + Domains::BulkRenew::SingleDomainRenew.run(domain: domain, + period: period, + unit: unit, + registrar: registrar) + end end end end From fafb02e9a04e463f5c1f39c2c215f55ac2838792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 15 Dec 2020 11:32:55 +0200 Subject: [PATCH 084/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60d7c1e24..59ec26c4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +15.12.2020 +* improved logic for domain list request in registrant API [#1750](https://github.com/internetee/registry/pull/1750) + 14.12.2020 * Refactored domain cron jobs for interactors [#1767](https://github.com/internetee/registry/issues/1767) From 13455b398cc9628c51dfd24013cd8f04daa8b5d8 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 15 Dec 2020 16:43:37 +0500 Subject: [PATCH 085/106] Add test & error message if not enough funds for renew --- app/interactions/domains/bulk_renew/start.rb | 1 + config/locales/en.yml | 1 + .../registrar_area/bulk_change/bulk_renew_test.rb | 15 +++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/app/interactions/domains/bulk_renew/start.rb b/app/interactions/domains/bulk_renew/start.rb index d407afade..a0a2f9bf0 100644 --- a/app/interactions/domains/bulk_renew/start.rb +++ b/app/interactions/domains/bulk_renew/start.rb @@ -42,6 +42,7 @@ module Domains def manage_errors(task) errors.merge!(task.errors) unless task.valid? + errors.add(:domain, I18n.t('not_enough_funds')) unless task.result end def run_task(domain) diff --git a/config/locales/en.yml b/config/locales/en.yml index 3547b049f..22f29a6e3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -590,6 +590,7 @@ en: billing_failure_credit_balance_low: 'Billing failure - credit balance low' billing_failure_credit_balance_low_for_domain: 'Billing failure - credit balance low for %{domain}' domain_renew_error_for_domain: 'Domain renew error for %{domain}' + not_enough_funds: 'Not enough funds for renew domains' create: 'Create' activity_type: 'Activity type' receipt_date_from: 'Receipt date from' diff --git a/test/system/registrar_area/bulk_change/bulk_renew_test.rb b/test/system/registrar_area/bulk_change/bulk_renew_test.rb index bcb6c3d66..41c045903 100644 --- a/test/system/registrar_area/bulk_change/bulk_renew_test.rb +++ b/test/system/registrar_area/bulk_change/bulk_renew_test.rb @@ -37,4 +37,19 @@ class BulkRenewTest < ApplicationSystemTestCase assert_text 'invalid.test' assert_no_text 'shop.test' end + + def test_bulk_renew_checks_balance + sign_in users(:api_bestnames) + @price.update(price_cents: 99999999) + travel_to Time.zone.parse('2010-07-05 10:30') + + visit new_registrar_bulk_change_url + click_link('Bulk renew') + select '1 year', from: 'Period' + click_button 'Filter' + click_button 'Renew' + + assert_text 'Not enough funds for renew domains' + + end end From 06a59c9aebd9c8e303bfa2d6329db1711db4a6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 15 Dec 2020 18:57:43 +0200 Subject: [PATCH 086/106] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59ec26c4c..d0cd1822c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ 15.12.2020 -* improved logic for domain list request in registrant API [#1750](https://github.com/internetee/registry/pull/1750) +* 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) From f1f8dba8254868d964de7bbb907854f2d5eed8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 16 Dec 2020 16:47:52 +0200 Subject: [PATCH 087/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cd1822c..28d3fd67d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From b833110ddd7294044692169718baafd381cec657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Thu, 17 Dec 2020 18:31:45 +0200 Subject: [PATCH 088/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d3fd67d..0907d33e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From b8aeba6beb8d582bc04666412d21ae643476a14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Dec 2020 14:41:34 +0200 Subject: [PATCH 089/106] Move bulk domain renew BL to REPP --- .../registrar/bulk_change_controller.rb | 16 +++--- .../repp/v1/domains/renews_controller.rb | 51 +++++++++++++++++++ app/models/depp/domain.rb | 9 ++++ .../bulk_change/_bulk_renew_form.html.erb | 4 +- config/routes.rb | 1 + 5 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 app/controllers/repp/v1/domains/renews_controller.rb diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 1dc5282a7..1c3d85cc1 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -13,12 +13,14 @@ class Registrar set_form_data if ready_to_renew? - domains = Epp::Domain.where(id: domain_ids_for_bulk_renew).to_a - task = renew_task(domains) - flash[:notice] = flash_message(task) + res = Depp::Domain.bulk_renew(domain_ids_for_bulk_renew, params[:period], + current_registrar_user.registrar) + + flash_message(JSON.parse(res)) else flash[:notice] = nil end + render file: 'registrar/bulk_change/new', locals: { active_tab: :bulk_renew } end @@ -60,12 +62,8 @@ class Registrar registrar: current_registrar_user.registrar) end - def flash_message(task) - if task.valid? - t(:bulk_renew_completed) - else - task.errors.full_messages.join(' and ') - end + def flash_message(res) + flash[:notice] = res['code'] == 1000 ? t(:bulk_renew_completed) : res['message'] end end end diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb new file mode 100644 index 000000000..46dd9fbba --- /dev/null +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -0,0 +1,51 @@ +module Repp + module V1 + module Domains + class RenewsController < BaseController + def bulk_renew + @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? + + 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: 2304, msg: renew.errors.full_messages.join(',') } + handle_errors + end + + private + + 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_idn(idn) + domains << domain if domain + @epp_errors << { code: 2304, msg: "Object does not exist: #{idn}" } unless domain + end + + domains + end + end + end + end +end diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index 3bb3b7473..a2acde07a 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -30,6 +30,15 @@ module Depp ['10 years', '10y'], ] + def self.bulk_renew(domains, period, _registrar) + payload = { domains: domains, renew_period: period } + headers = { Authorization: 'Basic dGVzdDp0ZXN0MTIz' } + + RestClient.post("#{ENV['repp_url']}domains/renew/bulk", payload, headers).response + rescue RestClient::ExceptionWithResponse => e + e.response + end + def initialize(args = {}) self.current_user = args[:current_user] self.epp_xml = EppXml::Domain.new(cl_trid_prefix: current_user.tag) diff --git a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb index 239a36815..5db40365f 100644 --- a/app/views/registrar/bulk_change/_bulk_renew_form.html.erb +++ b/app/views/registrar/bulk_change/_bulk_renew_form.html.erb @@ -37,8 +37,8 @@ <%= f.label :domain_ids, t('.domain_ids') %>
    - <%= f.collection_check_boxes :domain_ids, @domains, :id, :name, - checked: @domains.map(&:id) do |b|%> + <%= f.collection_check_boxes :domain_ids, @domains, :name, :name, + checked: @domains.map(&:name) do |b|%>
    <%= b.check_box %> <%= b.label %> diff --git a/config/routes.rb b/config/routes.rb index 7bf1ecd39..2a2de1863 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -64,6 +64,7 @@ Rails.application.routes.draw do get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } post 'transfer', to: 'domains#transfer' patch 'contacts', to: 'domains/contacts#update' + post 'renew/bulk', to: 'domains/renews#bulk_renew' end end end From 240da481e567b61575b10800bda88067a437a64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Fri, 18 Dec 2020 15:53:04 +0200 Subject: [PATCH 090/106] Generate REPP auth token for bulk renew --- app/controllers/registrar/bulk_change_controller.rb | 2 +- app/models/depp/domain.rb | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 1c3d85cc1..1e8220aa5 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -14,7 +14,7 @@ class Registrar if ready_to_renew? res = Depp::Domain.bulk_renew(domain_ids_for_bulk_renew, params[:period], - current_registrar_user.registrar) + current_registrar_user) flash_message(JSON.parse(res)) else diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index a2acde07a..17fadab65 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -30,9 +30,10 @@ module Depp ['10 years', '10y'], ] - def self.bulk_renew(domains, period, _registrar) + def self.bulk_renew(domains, period, registrar) payload = { domains: domains, renew_period: period } - headers = { Authorization: 'Basic dGVzdDp0ZXN0MTIz' } + token = Base64.urlsafe_encode64("#{registrar.username}:#{registrar.plain_text_password}") + headers = { Authorization: "Basic #{token}" } RestClient.post("#{ENV['repp_url']}domains/renew/bulk", payload, headers).response rescue RestClient::ExceptionWithResponse => e From 66114aa648bb63d4296e01d5c06577300edbefba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 13:30:30 +0200 Subject: [PATCH 091/106] Create tests for REPP bulk renew, fix lingvistic issues with errors --- .../repp/v1/domains/renews_controller.rb | 34 +++++--- app/interactions/domains/bulk_renew/start.rb | 2 +- app/models/depp/domain.rb | 2 +- .../repp/v1/domains/bulk_renew_test.rb | 80 +++++++++++++++++++ 4 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 test/integration/repp/v1/domains/bulk_renew_test.rb diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 46dd9fbba..052228e67 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -2,26 +2,40 @@ 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: 2304, + 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 + @domains = bulk_renew_domains else @epp_errors << { code: 2005, msg: 'Domains attribute must be an array' } end return handle_errors if @epp_errors.any? - - 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: 2304, msg: renew.errors.full_messages.join(',') } - handle_errors end - private - def run_bulk_renew_task(domains, period) ::Domains::BulkRenew::Start.run(domains: domains, period_element: period, registrar: current_user.registrar) @@ -38,7 +52,7 @@ module Repp @epp_errors ||= [] domains = [] bulk_renew_params[:domains].each do |idn| - domain = Epp::Domain.find_by_idn(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 diff --git a/app/interactions/domains/bulk_renew/start.rb b/app/interactions/domains/bulk_renew/start.rb index a0a2f9bf0..f758b52cd 100644 --- a/app/interactions/domains/bulk_renew/start.rb +++ b/app/interactions/domains/bulk_renew/start.rb @@ -41,7 +41,7 @@ module Domains end def manage_errors(task) - errors.merge!(task.errors) unless task.valid? + task.errors.each { |k, v| errors.add(k, v) } unless task.valid? errors.add(:domain, I18n.t('not_enough_funds')) unless task.result end diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index 17fadab65..e37f03334 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -35,7 +35,7 @@ module Depp token = Base64.urlsafe_encode64("#{registrar.username}:#{registrar.plain_text_password}") headers = { Authorization: "Basic #{token}" } - RestClient.post("#{ENV['repp_url']}domains/renew/bulk", payload, headers).response + RestClient.post("http://localhost:3000/repp/v1/domains/renew/bulk", payload, headers) rescue RestClient::ExceptionWithResponse => e e.response end diff --git a/test/integration/repp/v1/domains/bulk_renew_test.rb b/test/integration/repp/v1/domains/bulk_renew_test.rb new file mode 100644 index 000000000..fde383682 --- /dev/null +++ b/test/integration/repp/v1/domains/bulk_renew_test.rb @@ -0,0 +1,80 @@ +require 'test_helper' + +class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest + def setup + travel_to Time.zone.parse('2010-07-05 10:30') + @user = users(:api_bestnames) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + @domain = domains(:hospital) + + @auth_headers = { 'Authorization' => token } + end + + def test_renews_domains + payload = { + "domains": [ + 'shop.test', + 'airport.test', + 'library.test' + ], + "renew_period": "1y" + } + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert json[:data][:updated_domains].include? 'shop.test' + assert json[:data][:updated_domains].include? 'airport.test' + assert json[:data][:updated_domains].include? 'library.test' + end + + def test_throws_error_when_domain_not_renewable + payload = { + "domains": [ + 'invalid.test', + ], + "renew_period": "1y" + } + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2304, json[:code] + assert_equal 'Domain renew error for invalid.test', json[:message] + end + + def test_throws_error_when_not_enough_balance + billing_prices(:renew_one_year).update(price_cents: 99999999) + payload = { + "domains": [ + 'invalid.test', + ], + "renew_period": "1y" + } + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2304, json[:code] + assert_equal 'Not enough funds for renew domains', json[:message] + end + + def test_throws_error_if_invalid_renew_period + payload = { + "domains": [ + 'shop.test' + ], + "renew_period": "nope" + } + + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2005, json[:code] + assert_equal 'Invalid renew period', json[:message] + end +end From 04944b8ac4680d493435254817a53a828ec316da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 14:19:27 +0200 Subject: [PATCH 092/106] Improve bulk renew tests --- .../registrar/bulk_change_controller.rb | 2 +- .../repp/v1/domains/renews_controller.rb | 6 +-- app/models/depp/domain.rb | 10 ---- app/models/repp_api.rb | 11 +++++ .../repp/v1/domains/bulk_renew_test.rb | 49 ++++++++++++------- .../bulk_change/bulk_renew_test.rb | 19 ++++++- 6 files changed, 62 insertions(+), 35 deletions(-) create mode 100644 app/models/repp_api.rb diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index 1e8220aa5..f4f6707a5 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -13,7 +13,7 @@ class Registrar set_form_data if ready_to_renew? - res = Depp::Domain.bulk_renew(domain_ids_for_bulk_renew, params[:period], + res = ReppApi.bulk_renew(domain_ids_for_bulk_renew, params[:period], current_registrar_user) flash_message(JSON.parse(res)) diff --git a/app/controllers/repp/v1/domains/renews_controller.rb b/app/controllers/repp/v1/domains/renews_controller.rb index 052228e67..6b016dd86 100644 --- a/app/controllers/repp/v1/domains/renews_controller.rb +++ b/app/controllers/repp/v1/domains/renews_controller.rb @@ -9,8 +9,8 @@ module Repp 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: 2304, - msg: renew.errors.keys.map { |k, _v| renew.errors[k] }.join(',') } + @epp_errors << { code: 2002, + msg: renew.errors.keys.map { |k, _v| renew.errors[k] }.join(', ') } handle_errors end @@ -21,7 +21,7 @@ module Repp 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" } + @epp_errors << { code: 2005, msg: 'Invalid renew period' } end def select_renewable_domains diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index e37f03334..3bb3b7473 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -30,16 +30,6 @@ module Depp ['10 years', '10y'], ] - def self.bulk_renew(domains, period, registrar) - payload = { domains: domains, renew_period: period } - token = Base64.urlsafe_encode64("#{registrar.username}:#{registrar.plain_text_password}") - headers = { Authorization: "Basic #{token}" } - - RestClient.post("http://localhost:3000/repp/v1/domains/renew/bulk", payload, headers) - rescue RestClient::ExceptionWithResponse => e - e.response - end - def initialize(args = {}) self.current_user = args[:current_user] self.epp_xml = EppXml::Domain.new(cl_trid_prefix: current_user.tag) diff --git a/app/models/repp_api.rb b/app/models/repp_api.rb new file mode 100644 index 000000000..40c080a0b --- /dev/null +++ b/app/models/repp_api.rb @@ -0,0 +1,11 @@ +class ReppApi + def self.bulk_renew(domains, period, registrar) + payload = { domains: domains, renew_period: period } + token = Base64.urlsafe_encode64("#{registrar.username}:#{registrar.plain_text_password}") + headers = { Authorization: "Basic #{token}" } + + RestClient.post("#{ENV['repp_url']}domains/renew/bulk", payload, headers) + rescue RestClient::ExceptionWithResponse => e + e.response + end +end diff --git a/test/integration/repp/v1/domains/bulk_renew_test.rb b/test/integration/repp/v1/domains/bulk_renew_test.rb index fde383682..4cec91914 100644 --- a/test/integration/repp/v1/domains/bulk_renew_test.rb +++ b/test/integration/repp/v1/domains/bulk_renew_test.rb @@ -6,7 +6,6 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest @user = users(:api_bestnames) token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") token = "Basic #{token}" - @domain = domains(:hospital) @auth_headers = { 'Authorization' => token } end @@ -20,15 +19,22 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest ], "renew_period": "1y" } - post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload - json = JSON.parse(response.body, symbolize_names: true) - assert_response :ok - assert_equal 1000, json[:code] - assert_equal 'Command completed successfully', json[:message] - assert json[:data][:updated_domains].include? 'shop.test' - assert json[:data][:updated_domains].include? 'airport.test' - assert json[:data][:updated_domains].include? 'library.test' + assert_changes -> { Domain.find_by(name: 'shop.test').valid_to } do + assert_changes -> { Domain.find_by(name: 'airport.test').valid_to } do + assert_changes -> { Domain.find_by(name: 'library.test').valid_to } do + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :ok + assert_equal 1000, json[:code] + assert_equal 'Command completed successfully', json[:message] + assert json[:data][:updated_domains].include? 'shop.test' + assert json[:data][:updated_domains].include? 'airport.test' + assert json[:data][:updated_domains].include? 'library.test' + end + end + end end def test_throws_error_when_domain_not_renewable @@ -38,12 +44,14 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest ], "renew_period": "1y" } - post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload - json = JSON.parse(response.body, symbolize_names: true) + assert_no_changes -> { Domain.find_by(name: 'invalid.test').valid_to } do + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) - assert_response :bad_request - assert_equal 2304, json[:code] - assert_equal 'Domain renew error for invalid.test', json[:message] + assert_response :bad_request + assert_equal 2002, json[:code] + assert_equal 'Domain renew error for invalid.test', json[:message] + end end def test_throws_error_when_not_enough_balance @@ -54,12 +62,15 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest ], "renew_period": "1y" } - post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload - json = JSON.parse(response.body, symbolize_names: true) - assert_response :bad_request - assert_equal 2304, json[:code] - assert_equal 'Not enough funds for renew domains', json[:message] + assert_no_changes -> { Domain.find_by(name: 'invalid.test').valid_to } do + post "/repp/v1/domains/renew/bulk", headers: @auth_headers, params: payload + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 2002, json[:code] + assert_equal 'Not enough funds for renew domains', json[:message] + end end def test_throws_error_if_invalid_renew_period diff --git a/test/system/registrar_area/bulk_change/bulk_renew_test.rb b/test/system/registrar_area/bulk_change/bulk_renew_test.rb index 41c045903..5e1704afd 100644 --- a/test/system/registrar_area/bulk_change/bulk_renew_test.rb +++ b/test/system/registrar_area/bulk_change/bulk_renew_test.rb @@ -28,14 +28,21 @@ class BulkRenewTest < ApplicationSystemTestCase sign_in users(:api_bestnames) travel_to Time.zone.parse('2010-07-05 10:30') + req_body = { domains: ["shop.test", "airport.test", "library.test", "invalid.test"], renew_period: "1y" } + stub_request(:post, "#{ENV['repp_url']}domains/renew/bulk").with(body: req_body) + .to_return(status: 400, body: { + code: 2304, + message: "Domain renew error for invalid.test", + data: {} + }.to_json) + visit new_registrar_bulk_change_url click_link('Bulk renew') select '1 year', from: 'Period' click_button 'Filter' click_button 'Renew' - assert_text 'invalid.test' - assert_no_text 'shop.test' + assert_text 'Domain renew error for invalid.test' end def test_bulk_renew_checks_balance @@ -43,6 +50,14 @@ class BulkRenewTest < ApplicationSystemTestCase @price.update(price_cents: 99999999) travel_to Time.zone.parse('2010-07-05 10:30') + req_body = { domains: ["shop.test", "airport.test", "library.test", "invalid.test"], renew_period: "1y" } + stub_request(:post, "#{ENV['repp_url']}domains/renew/bulk").with(body: req_body) + .to_return(status: 400, body: { + code: 2304, + message: "Not enough funds for renew domains", + data: {} + }.to_json) + visit new_registrar_bulk_change_url click_link('Bulk renew') select '1 year', from: 'Period' From 01f6abb0d2d42b5fde8ec6e94afc0b5a0b152274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 14:41:19 +0200 Subject: [PATCH 093/106] Remove listen --- Gemfile | 1 - Gemfile.lock | 7 ------- 2 files changed, 8 deletions(-) diff --git a/Gemfile b/Gemfile index 9aad8b7ae..9bbcba254 100644 --- a/Gemfile +++ b/Gemfile @@ -80,7 +80,6 @@ gem 'directo', github: 'internetee/directo', branch: 'master' group :development, :test do - gem 'listen' gem 'pry', '0.10.1' gem 'puma' end diff --git a/Gemfile.lock b/Gemfile.lock index 3c9da920e..2a0bb55b1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -250,9 +250,6 @@ GEM kaminari-core (= 1.2.1) kaminari-core (1.2.1) libxml-ruby (3.2.0) - listen (3.3.3) - 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) @@ -366,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) @@ -516,7 +510,6 @@ DEPENDENCIES jquery-ui-rails (= 5.0.5) kaminari lhv! - listen minitest (~> 5.14) money-rails nokogiri From e763411e5cfca571402c01213afe5ea055d5d09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 14:43:30 +0200 Subject: [PATCH 094/106] Fix CC issues --- app/controllers/registrar/bulk_change_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb index f4f6707a5..801ab0516 100644 --- a/app/controllers/registrar/bulk_change_controller.rb +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -14,7 +14,7 @@ class Registrar if ready_to_renew? res = ReppApi.bulk_renew(domain_ids_for_bulk_renew, params[:period], - current_registrar_user) + current_registrar_user) flash_message(JSON.parse(res)) else From aac7a634874ecc05489e553a5e093805fc0cfe66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 16:49:39 +0200 Subject: [PATCH 095/106] Use plain Net::HTTP for bulk renew, include webclient certs --- app/models/repp_api.rb | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/app/models/repp_api.rb b/app/models/repp_api.rb index 40c080a0b..15ded62c5 100644 --- a/app/models/repp_api.rb +++ b/app/models/repp_api.rb @@ -1,11 +1,40 @@ class ReppApi def self.bulk_renew(domains, period, registrar) payload = { domains: domains, renew_period: period } - token = Base64.urlsafe_encode64("#{registrar.username}:#{registrar.plain_text_password}") - headers = { Authorization: "Basic #{token}" } + uri = URI.parse("#{ENV['repp_url']}domains/renew/bulk") + request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') + request.body = payload.to_json + request.basic_auth(registrar.username, registrar.plain_text_password) - RestClient.post("#{ENV['repp_url']}domains/renew/bulk", payload, headers) - rescue RestClient::ExceptionWithResponse => e - e.response + if Rails.env.test? + response = + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| + http.request(request) + end + elsif Rails.env.development? + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + response = + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + verify_mode: OpenSSL::SSL::VERIFY_NONE, + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + else + client_cert = File.read(ENV['cert_path']) + client_key = File.read(ENV['key_path']) + response = + Net::HTTP.start(uri.hostname, uri.port, + use_ssl: (uri.scheme == 'https'), + cert: OpenSSL::X509::Certificate.new(client_cert), + key: OpenSSL::PKey::RSA.new(client_key)) do |http| + http.request(request) + end + end + response.body end end From aff8e025bcfa3e1fd0735fb444a96839ed913d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Mon, 21 Dec 2020 17:43:11 +0200 Subject: [PATCH 096/106] Move webclient cert appending to separate method --- app/models/repp_api.rb | 46 +++++++++++++----------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/app/models/repp_api.rb b/app/models/repp_api.rb index 15ded62c5..92e7a22c7 100644 --- a/app/models/repp_api.rb +++ b/app/models/repp_api.rb @@ -2,39 +2,21 @@ class ReppApi def self.bulk_renew(domains, period, registrar) payload = { domains: domains, renew_period: period } uri = URI.parse("#{ENV['repp_url']}domains/renew/bulk") - request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') - request.body = payload.to_json - request.basic_auth(registrar.username, registrar.plain_text_password) + req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') + req.body = payload.to_json - if Rails.env.test? - response = - Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http| - http.request(request) - end - elsif Rails.env.development? - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = - Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - verify_mode: OpenSSL::SSL::VERIFY_NONE, - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end - else - client_cert = File.read(ENV['cert_path']) - client_key = File.read(ENV['key_path']) - response = - Net::HTTP.start(uri.hostname, uri.port, - use_ssl: (uri.scheme == 'https'), - cert: OpenSSL::X509::Certificate.new(client_cert), - key: OpenSSL::PKey::RSA.new(client_key)) do |http| - http.request(request) - end + 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 + http = Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) + unless Rails.env.test? + http.cert = OpenSSL::X509::Certificate.new(File.read(ENV['cert_path'])) + http.key = OpenSSL::PKey::RSA.new(File.read(ENV['key_path'])) end - response.body + http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development? || Rails.env.test? + + http.request(request) end end From f80c597be89e044c4d12d26fd56d7e069d09bf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Mon, 21 Dec 2020 18:09:16 +0200 Subject: [PATCH 097/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0907d33e1..59e867d1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From 66f341dc8542f429e75366b6b4ad48bae90ff3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 14:03:52 +0200 Subject: [PATCH 098/106] Fix REPP bulk renew SSL CA vericication --- app/models/repp_api.rb | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/app/models/repp_api.rb b/app/models/repp_api.rb index 92e7a22c7..a752a15af 100644 --- a/app/models/repp_api.rb +++ b/app/models/repp_api.rb @@ -10,13 +10,24 @@ class ReppApi def self.request(request, uri, registrar:) request.basic_auth(registrar.username, registrar.plain_text_password) if registrar - http = Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) - unless Rails.env.test? - http.cert = OpenSSL::X509::Certificate.new(File.read(ENV['cert_path'])) - http.key = OpenSSL::PKey::RSA.new(File.read(ENV['key_path'])) - end - http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development? || Rails.env.test? + 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) - http.request(request) + 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 From 1d3c70ae344eeda9513875157186ec38918553ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Tue, 22 Dec 2020 14:32:53 +0200 Subject: [PATCH 099/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e867d1c..fa814db62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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) From 8f25175cec848f43bd7b7f1b7f6c3b34dfa39dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 16:08:15 +0200 Subject: [PATCH 100/106] Fix bulk nameserver notification handling --- app/controllers/registrar/nameservers_controller.rb | 7 ++++--- app/views/registrar/bulk_change/_api_errors.html.erb | 4 ++++ .../domain_transfers/form/_api_errors.html.erb | 4 ++++ .../registrar_area/bulk_change/nameserver_test.rb | 12 +++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/controllers/registrar/nameservers_controller.rb b/app/controllers/registrar/nameservers_controller.rb index c8c88c8ca..2a22476be 100644 --- a/app/controllers/registrar/nameservers_controller.rb +++ b/app/controllers/registrar/nameservers_controller.rb @@ -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 diff --git a/app/views/registrar/bulk_change/_api_errors.html.erb b/app/views/registrar/bulk_change/_api_errors.html.erb index 56bf8c404..8d8862959 100644 --- a/app/views/registrar/bulk_change/_api_errors.html.erb +++ b/app/views/registrar/bulk_change/_api_errors.html.erb @@ -1,9 +1,13 @@ <% if @api_errors %>
      + <% if @api_errors.is_a?(String) %> +
    • <%= @api_errors %>
    • + <% else %> <% @api_errors.each do |error| %>
    • <%= error[:title] %>
    • <% end %> + <% end %>
    <% end %> diff --git a/app/views/registrar/domain_transfers/form/_api_errors.html.erb b/app/views/registrar/domain_transfers/form/_api_errors.html.erb index 56bf8c404..8d8862959 100644 --- a/app/views/registrar/domain_transfers/form/_api_errors.html.erb +++ b/app/views/registrar/domain_transfers/form/_api_errors.html.erb @@ -1,9 +1,13 @@ <% if @api_errors %>
      + <% if @api_errors.is_a?(String) %> +
    • <%= @api_errors %>
    • + <% else %> <% @api_errors.each do |error| %>
    • <%= error[:title] %>
    • <% end %> + <% end %>
    <% end %> diff --git a/test/system/registrar_area/bulk_change/nameserver_test.rb b/test/system/registrar_area/bulk_change/nameserver_test.rb index 3d4b4dc70..48806df7a 100644 --- a/test/system/registrar_area/bulk_change/nameserver_test.rb +++ b/test/system/registrar_area/bulk_change/nameserver_test.rb @@ -15,10 +15,12 @@ class RegistrarAreaNameserverBulkChangeTest < ApplicationSystemTestCase request_stub = stub_request(:put, /registrar\/nameservers/).with(body: request_body, headers: { 'Content-type' => Mime[:json] }, basic_auth: ['test_goodnames', 'testtest']) - .to_return(body: { data: [{ - type: 'nameserver', - id: 'new-ns.bestnames.test'}], - affected_domains: ["airport.test", "shop.test"]}.to_json, status: 200) + .to_return(body: { data: { + type: 'nameserver', + id: 'new-ns.bestnames.test', + affected_domains: ["airport.test", "shop.test"] + } + }.to_json, status: 200) visit registrar_domains_url click_link 'Bulk change' @@ -38,7 +40,7 @@ class RegistrarAreaNameserverBulkChangeTest < ApplicationSystemTestCase def test_fails_gracefully stub_request(:put, /registrar\/nameservers/).to_return(status: 400, - body: { errors: [{ title: 'epic fail' }] }.to_json, + body: { message: 'epic fail' }.to_json, headers: { 'Content-type' => Mime[:json] }) visit registrar_domains_url From 903044263a6dbaa67ada805850a6ccabd1b0aa8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 17:58:18 +0200 Subject: [PATCH 101/106] Fix bulk tech contact change notifications --- app/controllers/registrar/tech_contacts_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 1d459ef0f..ba15c5516 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -43,16 +43,16 @@ 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 redirect_to registrar_domains_url else - @error = parsed_response[:error] + @error = parsed_response[:message] render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact } end end From 8fffe6e73661c840817a6493778af4b7afb97a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 19:05:06 +0200 Subject: [PATCH 102/106] Fix tech contact / bulk transfer notifications --- .../registrar/domain_transfers_controller.rb | 6 ++++-- .../registrar/tech_contacts_controller.rb | 4 ++-- app/models/tech_domain_contact.rb | 17 +++++++++-------- .../bulk_change/_tech_contact_form.html.erb | 2 +- .../locales/registrar/domain_transfers.en.yml | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/app/controllers/registrar/domain_transfers_controller.rb b/app/controllers/registrar/domain_transfers_controller.rb index ca08c73cf..03874adb5 100644 --- a/app/controllers/registrar/domain_transfers_controller.rb +++ b/app/controllers/registrar/domain_transfers_controller.rb @@ -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', success: 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 diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index ba15c5516..057d01857 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -49,10 +49,10 @@ class Registrar 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[:message] + @error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message] render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact } end end diff --git a/app/models/tech_domain_contact.rb b/app/models/tech_domain_contact.rb index 04f36c4e4..92799061c 100644 --- a/app/models/tech_domain_contact.rb +++ b/app/models/tech_domain_contact.rb @@ -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 diff --git a/app/views/registrar/bulk_change/_tech_contact_form.html.erb b/app/views/registrar/bulk_change/_tech_contact_form.html.erb index dc0693599..2848e3634 100644 --- a/app/views/registrar/bulk_change/_tech_contact_form.html.erb +++ b/app/views/registrar/bulk_change/_tech_contact_form.html.erb @@ -1,7 +1,7 @@ <%= form_tag registrar_tech_contacts_path, method: :patch, class: 'form-horizontal' do %> <% if @error %>
    - <%= @error[:message] %> + <%= @error %>
    <% end %> diff --git a/config/locales/registrar/domain_transfers.en.yml b/config/locales/registrar/domain_transfers.en.yml index c146a5fd1..fd39e54f7 100644 --- a/config/locales/registrar/domain_transfers.en.yml +++ b/config/locales/registrar/domain_transfers.en.yml @@ -6,7 +6,7 @@ en: create: header: Domain transfer - transferred: "%{count} domains have been successfully transferred" + transferred: "%{count} domains have been successfully transferred. Failed domains: %{failed}" form: submit_btn: Transfer From 7c2e43197b2321ef2c763327a46db503121d3b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 19:56:51 +0200 Subject: [PATCH 103/106] Fix bulk action notifications --- app/controllers/registrar/domain_transfers_controller.rb | 2 +- app/views/registrar/bulk_change/_api_errors.html.erb | 4 ++++ .../registrar/domain_transfers/form/_api_errors.html.erb | 4 ++++ .../registrar_area/bulk_change/bulk_transfer_test.rb | 8 ++++---- .../registrar_area/bulk_change/tech_contact_test.rb | 6 +++--- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/controllers/registrar/domain_transfers_controller.rb b/app/controllers/registrar/domain_transfers_controller.rb index 03874adb5..584a50d33 100644 --- a/app/controllers/registrar/domain_transfers_controller.rb +++ b/app/controllers/registrar/domain_transfers_controller.rb @@ -56,7 +56,7 @@ class Registrar if response.code == '200' failed = parsed_response[:data][:failed].each(&:domain_name).join(', ') - flash[:notice] = t('.transferred', success: parsed_response[:data][:success].size, + flash[:notice] = t('.transferred', count: parsed_response[:data][:success].size, failed: failed) redirect_to registrar_domains_url else diff --git a/app/views/registrar/bulk_change/_api_errors.html.erb b/app/views/registrar/bulk_change/_api_errors.html.erb index 56bf8c404..8d8862959 100644 --- a/app/views/registrar/bulk_change/_api_errors.html.erb +++ b/app/views/registrar/bulk_change/_api_errors.html.erb @@ -1,9 +1,13 @@ <% if @api_errors %>
      + <% if @api_errors.is_a?(String) %> +
    • <%= @api_errors %>
    • + <% else %> <% @api_errors.each do |error| %>
    • <%= error[:title] %>
    • <% end %> + <% end %>
    <% end %> diff --git a/app/views/registrar/domain_transfers/form/_api_errors.html.erb b/app/views/registrar/domain_transfers/form/_api_errors.html.erb index 56bf8c404..8d8862959 100644 --- a/app/views/registrar/domain_transfers/form/_api_errors.html.erb +++ b/app/views/registrar/domain_transfers/form/_api_errors.html.erb @@ -1,9 +1,13 @@ <% if @api_errors %>
      + <% if @api_errors.is_a?(String) %> +
    • <%= @api_errors %>
    • + <% else %> <% @api_errors.each do |error| %>
    • <%= error[:title] %>
    • <% end %> + <% end %>
    <% end %> diff --git a/test/system/registrar_area/bulk_change/bulk_transfer_test.rb b/test/system/registrar_area/bulk_change/bulk_transfer_test.rb index a531ff4dc..820b1cf96 100644 --- a/test/system/registrar_area/bulk_change/bulk_transfer_test.rb +++ b/test/system/registrar_area/bulk_change/bulk_transfer_test.rb @@ -11,9 +11,9 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase request_stub = stub_request(:post, /domains\/transfer/).with(body: request_body, headers: headers, basic_auth: ['test_goodnames', 'testtest']) - .to_return(body: { data: [{ - type: 'domain_transfer' - }] }.to_json, status: 200) + .to_return(body: { data: { success: [{ type: 'domain_transfer', domain_name: 'shop.test' }], + failed: [] + } }.to_json, status: 200) visit registrar_domains_url click_link 'Bulk change' @@ -27,7 +27,7 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase end def test_fail_gracefully - body = { errors: [{ title: 'epic fail' }] }.to_json + body = { message: 'epic fail' }.to_json headers = { 'Content-type' => Mime[:json] } stub_request(:post, /domains\/transfer/).to_return(status: 400, body: body, headers: headers) diff --git a/test/system/registrar_area/bulk_change/tech_contact_test.rb b/test/system/registrar_area/bulk_change/tech_contact_test.rb index c678e8f34..e08457f60 100644 --- a/test/system/registrar_area/bulk_change/tech_contact_test.rb +++ b/test/system/registrar_area/bulk_change/tech_contact_test.rb @@ -9,8 +9,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase request_stub = stub_request(:patch, /domains\/contacts/) .with(body: { current_contact_id: 'william-001', new_contact_id: 'john-001' }, basic_auth: ['test_bestnames', 'testtest']) - .to_return(body: { affected_domains: %w[foo.test bar.test], - skipped_domains: %w[baz.test qux.test] }.to_json, + .to_return(body: { data: { affected_domains: %w[foo.test bar.test], + skipped_domains: %w[baz.test qux.test] } }.to_json, status: 200) visit registrar_domains_url @@ -30,7 +30,7 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase def test_fails_gracefully stub_request(:patch, /domains\/contacts/) .to_return(status: 400, - body: { error: { message: 'epic fail' } }.to_json, + body: { message: 'epic fail' }.to_json, headers: { 'Content-type' => Mime[:json] }) visit registrar_domains_url From 490467b5d922b99d18dca68b50d4aa479dbf229b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Tue, 22 Dec 2020 20:15:01 +0200 Subject: [PATCH 104/106] REPP: check webclient IPs to bypass registrar IP whitelist --- app/controllers/repp/v1/base_controller.rb | 24 +++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index ca9ef6fb5..76735a686 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -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,32 @@ 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) From db4f57308b83ffbe77cc9ce69f1867e783319077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 23 Dec 2020 11:30:29 +0200 Subject: [PATCH 105/106] Fix some CC issues --- app/controllers/registrar/tech_contacts_controller.rb | 6 ++++-- app/controllers/repp/v1/base_controller.rb | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb index 057d01857..001651250 100644 --- a/app/controllers/registrar/tech_contacts_controller.rb +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -43,10 +43,12 @@ class Registrar if response.code == '200' notices = [t('.replaced')] - notices << "#{t('.affected_domains')}: #{parsed_response[:data][:affected_domains].join(', ')}" + notices << "#{t('.affected_domains')}: " \ + "#{parsed_response[:data][:affected_domains].join(', ')}" if parsed_response[:data][:skipped_domains] - notices << "#{t('.skipped_domains')}: #{parsed_response[:data][:skipped_domains].join(', ')}" + notices << "#{t('.skipped_domains')}: " \ + "#{parsed_response[:data][:skipped_domains].join(', ')}" end flash[:notice] = notices.join(', ') diff --git a/app/controllers/repp/v1/base_controller.rb b/app/controllers/repp/v1/base_controller.rb index 76735a686..2814ce2da 100644 --- a/app/controllers/repp/v1/base_controller.rb +++ b/app/controllers/repp/v1/base_controller.rb @@ -104,6 +104,7 @@ module Repp def webclient_request? return if Rails.env.test? + ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip) end From bc69e05c91141d80417ce7db6071bbc2390c555e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20V=C3=B5hmar?= Date: Wed, 23 Dec 2020 12:38:29 +0200 Subject: [PATCH 106/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa814db62..e9135d83f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +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)