From 2c34ac2311e02b937a9af8f0f1e7f857c5a13495 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 29 Nov 2024 15:03:00 +0200 Subject: [PATCH] feat: add expire_at field to domain reservation responses Add expiration time information to domain reservation responses across all endpoints: - Add FREE_RESERVATION_EXPIRY (7 days) and PAID_RESERVATION_EXPIRY (1 year) constants - Update ReservedDomain model to set expire_at on creation - Modify ReserveDomainInvoice#build_reserved_domains_output to include expire_at - Update API responses to include expire_at in reserved_domains data - Add comprehensive tests for expiration time handling This change ensures consistent expiration time handling across both free and paid domain reservations, with proper validation in the test suite. --- .../long_reserve_domains_status_controller.rb | 4 +- .../reserve_domains_controller.rb | 8 +++- app/models/reserve_domain_invoice.rb | 24 ++++++++++-- app/models/reserved_domain.rb | 8 +++- ..._reserve_domains_status_controller_test.rb | 38 +++++++++++++++++- .../reserve_domains_controller_test.rb | 39 +++++++++++++++++++ test/models/reserve_domain_invoice_test.rb | 14 +++++-- 7 files changed, 121 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/v1/business_registry/long_reserve_domains_status_controller.rb b/app/controllers/api/v1/business_registry/long_reserve_domains_status_controller.rb index 8f7bc1b763..49a85acca5 100644 --- a/app/controllers/api/v1/business_registry/long_reserve_domains_status_controller.rb +++ b/app/controllers/api/v1/business_registry/long_reserve_domains_status_controller.rb @@ -7,10 +7,8 @@ class LongReserveDomainsStatusController < BaseController def show result = @reserved_domain_invoice.invoice_state - puts "result: #{result.inspect}" - if result.paid? - @reserved_domain_invoice.create_reserved_domains + @reserved_domain_invoice.create_paid_reserved_domains render json: { status: 'paid', message: result.message, reserved_domains: @reserved_domain_invoice.build_reserved_domains_output } else render json: { status: result.status, message: result.message, names: @reserved_domain_invoice.domain_names } diff --git a/app/controllers/api/v1/business_registry/reserve_domains_controller.rb b/app/controllers/api/v1/business_registry/reserve_domains_controller.rb index ed6e7ec561..5f3721cd78 100644 --- a/app/controllers/api/v1/business_registry/reserve_domains_controller.rb +++ b/app/controllers/api/v1/business_registry/reserve_domains_controller.rb @@ -11,7 +11,13 @@ def create if result.success render_success({ message: "Domains reserved successfully", - reserved_domains: result.reserved_domains.map { |domain| { name: domain.name, password: domain.password } } + reserved_domains: result.reserved_domains.map do |domain| + { + name: domain.name, + password: domain.password, + expire_at: domain.expire_at + } + end }, :created) else render_error(result.errors, :unprocessable_entity) diff --git a/app/models/reserve_domain_invoice.rb b/app/models/reserve_domain_invoice.rb index 827f82ad1b..51a685e6e7 100644 --- a/app/models/reserve_domain_invoice.rb +++ b/app/models/reserve_domain_invoice.rb @@ -73,7 +73,7 @@ def check_state_of_intersecting_invoices(domain_names) if invoice.pending? && result.paid? invoice.paid! - invoice.create_reserved_domains + invoice.create_paid_reserved_domains ReserveDomainInvoice.cancel_intersecting_invoices(domain_names) return true @@ -180,11 +180,27 @@ def invoice_state EisBilling::GetReservedDomainsInvoiceStatus.call(invoice_number: invoice_number, user_unique_id: metainfo) end - def create_reserved_domains - domain_names.map { |name| ReservedDomain.create(name: name) if ReservedDomain.find_by(name: name).nil? } + def create_paid_reserved_domains + domain_names.map do |name| + next if ReservedDomain.find_by(name: name).present? + + ReservedDomain.create( + name: name, + expire_at: Time.current + ReservedDomain::PAID_RESERVATION_EXPIRY + ) + end end def build_reserved_domains_output - domain_names.map { |name| ReservedDomain.where(name: name).pluck(:name, :password).to_h } + domain_names.map do |name| + domain = ReservedDomain.find_by(name: name) + next unless domain + + { + name: domain.name, + password: domain.password, + expire_at: domain.expire_at + } + end.compact end end diff --git a/app/models/reserved_domain.rb b/app/models/reserved_domain.rb index 922a21b85a..d379012d7f 100644 --- a/app/models/reserved_domain.rb +++ b/app/models/reserved_domain.rb @@ -14,6 +14,9 @@ class ReservedDomain < ApplicationRecord MAX_DOMAIN_NAME_PER_REQUEST = 20 + FREE_RESERVATION_EXPIRY = 7.days + PAID_RESERVATION_EXPIRY = 1.year + class << self def ransackable_associations(*) authorizable_ransackable_associations @@ -53,7 +56,10 @@ def reserve_domains_without_payment(domain_names) reserved_domains = [] available_domains.each do |domain_name| - reserved_domain = ReservedDomain.new(name: domain_name) + reserved_domain = ReservedDomain.new( + name: domain_name, + expire_at: Time.current + FREE_RESERVATION_EXPIRY + ) reserved_domain.regenerate_password reserved_domain.save reserved_domains << reserved_domain diff --git a/test/integration/api/business_registry/long_reserve_domains_status_controller_test.rb b/test/integration/api/business_registry/long_reserve_domains_status_controller_test.rb index 55c91a3e8e..f1e154b6d0 100644 --- a/test/integration/api/business_registry/long_reserve_domains_status_controller_test.rb +++ b/test/integration/api/business_registry/long_reserve_domains_status_controller_test.rb @@ -18,7 +18,8 @@ def setup body: { message: 'Payment received', invoice_status: 'paid', - invoice_number: @invoice.invoice_number + invoice_number: @invoice.invoice_number, + reserved_domain_names: @invoice.domain_names }, user_unique_id: @invoice.metainfo ) @@ -83,6 +84,41 @@ def setup assert_equal 'Error occurred', json_response['message'] end + test "shows paid status with expire_at for reserved domains" do + stub_billing_request( + status: 200, + body: { + message: 'Payment received', + invoice_status: 'paid', + invoice_number: @invoice.invoice_number, + reserved_domain_names: @invoice.domain_names + }, + user_unique_id: @invoice.metainfo + ) + + get api_v1_business_registry_long_reserve_domains_status_path( + invoice_number: @invoice.invoice_number, + user_unique_id: @invoice.metainfo + ), + headers: { 'Origin' => @allowed_origins.first, 'REMOTE_ADDR' => @valid_ip } + + assert_response :success + json_response = JSON.parse(response.body) + + assert_equal 'paid', json_response['status'] + assert_equal 'Payment received', json_response['message'] + + # Проверяем структуру reserved_domains + reserved_domain = json_response['reserved_domains'].first + assert_not_nil reserved_domain['name'] + assert_not_nil reserved_domain['password'] + assert_not_nil reserved_domain['expire_at'] + + # Проверяем, что expire_at установлен на 1 год + expire_at = Time.parse(reserved_domain['expire_at']) + assert_in_delta Time.current + ReservedDomain::PAID_RESERVATION_EXPIRY, expire_at, 5.seconds + end + private def stub_billing_request(status:, body:, user_unique_id: nil) diff --git a/test/integration/api/business_registry/reserve_domains_controller_test.rb b/test/integration/api/business_registry/reserve_domains_controller_test.rb index ec3ca8e6be..fa99897bdf 100644 --- a/test/integration/api/business_registry/reserve_domains_controller_test.rb +++ b/test/integration/api/business_registry/reserve_domains_controller_test.rb @@ -80,4 +80,43 @@ def setup json_response = JSON.parse(response.body) assert_includes json_response['error'], "The maximum number of domain names per request is #{ReservedDomain::MAX_DOMAIN_NAME_PER_REQUEST}" end + + test "should reserve multiple domains successfully with correct expiration" do + domain_names = ["new1.test", "new2.test"] + + assert_difference 'ReservedDomain.count', 2 do + post api_v1_business_registry_reserve_domains_path, + params: { domain_names: domain_names }, + headers: { 'Origin' => @allowed_origins.first, 'REMOTE_ADDR' => @valid_ip } + end + + assert_response :created + json_response = JSON.parse(response.body) + assert_equal "Domains reserved successfully", json_response['message'] + assert_equal 2, json_response['reserved_domains'].length + + json_response['reserved_domains'].each do |domain| + assert domain_names.include?(domain['name']) + assert_not_nil domain['password'] + assert_not_nil domain['expire_at'] + + expire_at = Time.parse(domain['expire_at']) + assert_in_delta Time.current + ReservedDomain::FREE_RESERVATION_EXPIRY, expire_at, 5.seconds + end + end + + test "should set correct expiration time for free reservations" do + domain_name = "new1.test" + + post api_v1_business_registry_reserve_domains_path, + params: { domain_names: [domain_name] }, + headers: { 'Origin' => @allowed_origins.first, 'REMOTE_ADDR' => @valid_ip } + + assert_response :created + json_response = JSON.parse(response.body) + domain = json_response['reserved_domains'].first + + expire_at = Time.parse(domain['expire_at']) + assert_in_delta Time.current + ReservedDomain::FREE_RESERVATION_EXPIRY, expire_at, 5.seconds + end end \ No newline at end of file diff --git a/test/models/reserve_domain_invoice_test.rb b/test/models/reserve_domain_invoice_test.rb index ace3d10e0f..9bd7f80deb 100644 --- a/test/models/reserve_domain_invoice_test.rb +++ b/test/models/reserve_domain_invoice_test.rb @@ -49,17 +49,23 @@ def teardown invoice = ReserveDomainInvoice.create(invoice_number: '12345', domain_names: @domain_names, metainfo: TEST_USER_UNIQUE_ID) assert_difference 'ReservedDomain.count', 2 do - invoice.create_reserved_domains + invoice.create_paid_reserved_domains end end test "builds correct output for reserved domains" do invoice = ReserveDomainInvoice.create(invoice_number: '12345', domain_names: @domain_names, metainfo: TEST_USER_UNIQUE_ID) - ReservedDomain.create(name: @domain_names.first, password: 'test123') + ReservedDomain.create( + name: @domain_names.first, + password: 'test123', + expire_at: Time.current + ReservedDomain::PAID_RESERVATION_EXPIRY + ) output = invoice.build_reserved_domains_output - assert_equal @domain_names.count, output.length - assert_equal 'test123', output.first[@domain_names.first] + assert_equal @domain_names.count - 1, output.length + domain_output = output.find { |d| d[:name] == @domain_names.first } + assert_equal 'test123', domain_output[:password] + assert_not_nil domain_output[:expire_at] end test "handles intersecting domains" do