diff --git a/Gemfile b/Gemfile index 26c025e..a2c04fa 100644 --- a/Gemfile +++ b/Gemfile @@ -34,6 +34,7 @@ gem 'turbo-rails' gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] gem 'uuidtools' # For unique IDs (used by the epp gem) gem 'view_component' +gem 'aasm' # gem "kredis" # gem "image_processing", "~> 1.2" diff --git a/Gemfile.lock b/Gemfile.lock index 3062a6a..1149b64 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,6 +27,8 @@ GIT GEM remote: https://rubygems.org/ specs: + aasm (5.5.0) + concurrent-ruby (~> 1.0) actioncable (7.0.8) actionpack (= 7.0.8) activesupport (= 7.0.8) @@ -235,6 +237,8 @@ GEM net-smtp (0.4.0) net-protocol nio4r (2.5.9) + nokogiri (1.15.4-aarch64-linux) + racc (~> 1.4) nokogiri (1.15.4-x86_64-linux) racc (~> 1.4) omniauth (2.1.1) @@ -443,10 +447,11 @@ GEM zeitwerk (2.6.12) PLATFORMS - x86_64-linux aarch64-linux-musl + x86_64-linux DEPENDENCIES + aasm annotate attr_encrypted bcrypt (~> 3.1.7) diff --git a/app/adapters/estonian_repp_adapter.rb b/app/adapters/estonian_repp_adapter.rb index 509c141..1789f6f 100644 --- a/app/adapters/estonian_repp_adapter.rb +++ b/app/adapters/estonian_repp_adapter.rb @@ -1,7 +1,7 @@ class EstonianReppAdapter include AdapterInterface - def create_domain(payload:) - EstonianTld::DomainService.new(tld: Tld.first).create(payload:) + def create_domain(domain:, pending_action:) + EstonianTld::DomainService.new(tld: Tld.first).create(domain, pending_action) end end diff --git a/app/broadcasts/estonian_tld/inform_registrant_service.rb b/app/broadcasts/estonian_tld/inform_registrant_service.rb new file mode 100644 index 0000000..a01518b --- /dev/null +++ b/app/broadcasts/estonian_tld/inform_registrant_service.rb @@ -0,0 +1,24 @@ +module EstonianTld + class InformRegistrantService < ApplicationService + attr_reader :message, :tld + + def initialize(params) + super + + @message = params[:message] + @tld = params[:tld] + end + + def call + post_call + end + + private + + def post_call + broadcast_later "dashboards_#{tld.uuid}", + 'dashboards/streams/registrant_replaced', + locals: { message: } + end + end +end diff --git a/app/controllers/registrant/domains_controller.rb b/app/controllers/registrant/domains_controller.rb index 670507d..345548a 100644 --- a/app/controllers/registrant/domains_controller.rb +++ b/app/controllers/registrant/domains_controller.rb @@ -7,7 +7,10 @@ def new end def index - @pending_actions = current_user.pending_actions + pending_actions = current_user.pending_actions.order(created_at: :desc) + @pagy, @pending_actions = pagy(pending_actions, items: 10, link_extra: 'data-turbo-action="advance"') + + @pagy_domain, @domains = pagy(current_user.domains.order(created_at: :desc), items: 10, link_extra: 'data-turbo-action="advance"') end def show; end @@ -15,35 +18,11 @@ def show; end def edit; end def create - # result = current_api_adapter.create_domain(payload: params[:domain]) - - # if result.success? - # redirect_to registrant_domains_path, notice: t('.success') - # else - # @domain = Domain.build_from_registrar(params[:domain]) - # flash.now[:alert] = result.errors - # render :new - # end - - # ============== - # TODO: - # + Create pending action "Create Domain" (Table i created) - # + If user not in contact list or he doesn't have a code, create contact with code (I implement this jov) - # + Generate Invoice for this action (Need implement this method in PendingAction model) - # + User pay and he redirected back (I created oneoff service object) - - # SHow banner that domain is creating (Need to implement) - # Create domain and Send this info to EPP (implement this job) - pending = PendingAction.create( user: current_user, action: :domain_create, status: :pending, - info: { - domain: params[:name], - reserved_pw: params[:reserved_pw], - period: params[:period], - }, + info: domain_params.to_h, ) @invoice = pending.create_invoice_by_pending_action @@ -65,5 +44,11 @@ def create def update; end def destroy; end + + private + + def domain_params + params.require(:domain).permit(:name, :period, :reserved_pw) + end end end \ No newline at end of file diff --git a/app/controllers/registrant/invoices/pay_invoices_controller.rb b/app/controllers/registrant/invoices/pay_invoices_controller.rb index ce6811c..2f89810 100644 --- a/app/controllers/registrant/invoices/pay_invoices_controller.rb +++ b/app/controllers/registrant/invoices/pay_invoices_controller.rb @@ -51,9 +51,16 @@ def callback status = parsed_response[:payment_state] == 'settled' ? :paid : :failed invoice = Invoice.find_by!(number: invoice_number) - invoice.update!(status: status) + + if invoice.update(status: status) + EstonianTld::CreateDomainJob.perform_later(invoice.pending_action) - redirect_to registrant_domains_path + flash.notice = t('.domain_is_creating') + redirect_to registrant_domains_path, status: :see_other + else + flash.alert = t('.failed') + redirect_to registrant_domains_path, status: :see_other + end end private diff --git a/app/controllers/registrant/pending_actions_controller.rb b/app/controllers/registrant/pending_actions_controller.rb new file mode 100644 index 0000000..0083a5e --- /dev/null +++ b/app/controllers/registrant/pending_actions_controller.rb @@ -0,0 +1,9 @@ +module Registrant + class PendingActionsController < ApplicationController + include Roles::RegistrantAbilitable + + def show + @pending_action = current_user.pending_actions.find_by(uuid: params[:uuid]) + end + end +end diff --git a/app/jobs/estonian_tld/create_contact_job.rb b/app/jobs/estonian_tld/create_contact_job.rb index b0b32f5..d64e606 100644 --- a/app/jobs/estonian_tld/create_contact_job.rb +++ b/app/jobs/estonian_tld/create_contact_job.rb @@ -4,10 +4,6 @@ class EstonianTld::CreateContactJob < ApplicationJob def perform(user) contact = Contact.find_by(ident: user.ident) - puts '====' - puts contact - puts contact.code.present? - if contact && contact.code.present? puts '== AU PIDAR' user.update!(code: contact.code) if user.code.blank? @@ -17,8 +13,6 @@ def perform(user) payload = contact_payload(user) response = EstonianTld::ContactService.new(tld: Tld.first).create_contact(payload:) - puts response - if response.success code = response.body["data"]["contact"]["code"] @@ -26,22 +20,16 @@ def perform(user) ActiveRecord::Base.transaction do contact.update!(code: code) user.update!(code: code) - puts "ai ame here" end else ActiveRecord::Base.transaction do user.update!(code: code) create_contact(user) - - puts "ai ame here" - end end else Rails.logger.info response.body["message"] end - - puts '=====' end def create_contact(registrant_user) diff --git a/app/jobs/estonian_tld/create_domain_job.rb b/app/jobs/estonian_tld/create_domain_job.rb index aaf578e..e5201f7 100644 --- a/app/jobs/estonian_tld/create_domain_job.rb +++ b/app/jobs/estonian_tld/create_domain_job.rb @@ -1,7 +1,94 @@ class EstonianTld::CreateDomainJob < ApplicationJob queue_as :critical - def perform(domain) - # TODO: Create domain in local database and send by EPP to registry + def perform(pending_action) + return if pending_action.completed? + + admin_contact = Contact.find_by(code: pending_action.user.code) + tech_contact = Contact.find_by(code: Setting['code_of_technical_contact'] || pending_action.user.code) + + expire_at = calculate_expiry(pending_action.info['period'].to_i) + + registrant_contact = Contact.find_by(code: pending_action.user.code) + + domain = Domain.find_by(name: pending_action.info['name']) + + if domain.nil? + domain = Domain.new( + name: pending_action.info['name'], + registrant_id: registrant_contact.id, + expire_at: expire_at, + reserved_pw: pending_action.info['reserved_pw'], + domain_contacts: [ + AdminDomainContact.new( + contact_id: admin_contact.id, + ), + TechDomainContact.new( + contact_id: tech_contact.id, + ), + ], + nameservers: Setting['default_nameserver_records'] || [], + dnssec_keys: Setting['dnssec_enabled'] ? Setting['default_dnssec_keys'] : [], + ) + REPP_ENDPOINT + + if domain.save + # response = EstonianTld::DomainService.new(tld: Tld.first).create(domain, pending_action) + + response = current_api_adapter.create_domain(domain: domain, pending_action: pending_action) + + if response.success + pending_action.update(status: :completed) + domain.update(state: :active) + else + pending_action.update(status: :failed, errors_in_response: response.body) + inform_registrant_service(tld: Tld.first, message: response.body) + + Rails.logger.info '------ error -----' + Rails.logger.info response.body + Rails.logger.info '------ error -----' + end + + Rails.logger.info "Domain #{domain.name} was created!" + else + Rails.logger.info domain.errors.inspect + end + end + + private + + def inform_registrant_service(tld:, message:) + EstonianTld::InformRegistrantService.call({ tld:, message: }) + end + + def ns_attrs(nameservers) + nameservers.map { |n| n.extract!(:hostname, :ipv4, :ipv6) } + end + + def contacts(contacts, type) + return [] unless contacts + + contacts.select { |c| c[:type] == type }.pluck(:code) + end + + # TODO: Need to complete this method + def domain_params(domain) + { + domain: { + name: domain.name, + reserved_pw: domain.reserved_pw, + registrant: domain.registrant.code, + # TODO: domain no store period unit value !!! period_unit: payload[:period][-1].to_s, + # TODO: domain no store perion value !!! period: payload[:period].to_i, + nameservers_attributes: ns_attrs(payload[:nameservers]), + admin_contacts: contacts(payload[:contacts], 'admin'), + tech_contacts: contacts(payload[:contacts], 'tech'), + dnskeys_attributes: payload[:dns_keys], + }, + } + end + + def calculate_expiry(period) + (Time.zone.now.advance(months: period) + 1.day).beginning_of_day end -end \ No newline at end of file +end diff --git a/app/models/pending_action.rb b/app/models/pending_action.rb index 1ea05ed..6bc532f 100644 --- a/app/models/pending_action.rb +++ b/app/models/pending_action.rb @@ -1,8 +1,43 @@ class PendingAction < ApplicationRecord + include AASM + belongs_to :user belongs_to :invoice, optional: true enum status: { pending: 100, completed: 200, declined: 300, failed: 400 } + + aasm column: :status, enum: true do + state :pending, initial: true + state :completed + state :declined + state :failed + + event :complete do + transitions from: :pending, to: :completed + end + + event :decline do + transitions from: :pending, to: :declined + end + + event :fail do + transitions from: :pending, to: :failed + end + end + + validate :unable_to_update + + def unable_to_update + return if pending? + return if invoice.issued? + + errors.add(:base, I18n.t('errors.messages.unable_to_update')) + end + + def can_i_edit_it? + pending? && invoice.issued? + end + enum action: { domain_create: 100, domain_update: 200, diff --git a/app/models/user.rb b/app/models/user.rb index f36f861..9a6ab68 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -30,9 +30,11 @@ class User < ApplicationRecord after_find :split_phone_into_code_and_number def self.from_omniauth(tara_params) - full_name = "#{tara_params.dig('info', 'given_name')} #{tara_params.dig('info', 'family_name')}" + full_name = "#{tara_params.dig('info', 'first_name')} #{tara_params.dig('info', 'last_name')}" ident = tara_params['uid'][2..] + print("TARA params: #{tara_params}") + user = User.find_or_initialize_by(ident:) user.name = full_name user.ident = ident @@ -55,4 +57,9 @@ def birthday(identity_code:) Date.parse(identity_code.slice(1..6)) end + def domains + contact = Contact.find_by(code: code) + Domain.where(registrant_id: contact.id) + end + end diff --git a/app/services/estonian_tld/domain_service.rb b/app/services/estonian_tld/domain_service.rb index 557cfaf..5de08a2 100644 --- a/app/services/estonian_tld/domain_service.rb +++ b/app/services/estonian_tld/domain_service.rb @@ -12,25 +12,28 @@ def domain_list(url_params: {}) connect(url: "#{tld.base_url}#{REPP_ENDPOINT}/domains?#{url_params.to_query}", method: 'get', params: {}, headers: nil) end - def create(payload:) - connect(url: "#{tld.base_url}#{REPP_ENDPOINT}/domains", method: 'post', params: domain_params(payload), headers: nil) + def create(domain, pending_action) + payload = parse_domain(domain, pending_action) + connect(url: "#{tld.base_url}#{REPP_ENDPOINT}/domains", method: 'post', params: payload, headers: nil) end private - def domain_params(payload) + def parse_domain(domain, pending_action) + period_in_months = pending_action.info['period'].to_i + { domain: { - name: payload[:name], - reserved_pw: payload[:reserved_pw], - registrant: payload[:registrant][:code], - period_unit: payload[:period][-1].to_s, - period: payload[:period].to_i, - nameservers_attributes: ns_attrs(payload[:nameservers]), - admin_contacts: contacts(payload[:contacts], 'admin'), - tech_contacts: contacts(payload[:contacts], 'tech'), - dnskeys_attributes: payload[:dns_keys], - }, + name: domain.name, + reserved_pw: domain.reserved_pw, + registrant: domain.registrant.code, + period_unit: 'm', + period: period_in_months.to_i, + nameservers_attributes: ns_attrs(domain.nameservers), + admin_contacts: contacts(domain.contacts, 'admin'), + tech_contacts: contacts(domain.contacts, 'tech'), + dnskeys_attributes: domain.dnssec_keys, + } } end diff --git a/app/views/dashboards/index.html.erb b/app/views/dashboards/index.html.erb index 0c39b75..076bd52 100644 --- a/app/views/dashboards/index.html.erb +++ b/app/views/dashboards/index.html.erb @@ -6,6 +6,7 @@ <% if admin? %> <%= turbo_stream_from "dashboards_#{@tld.uuid}" %>
+ <%= render 'dashboards/admin' %> <% elsif registrar? %> diff --git a/app/views/dashboards/streams/registrant_replaced.turbo_stream.erb b/app/views/dashboards/streams/registrant_replaced.turbo_stream.erb new file mode 100644 index 0000000..0d44089 --- /dev/null +++ b/app/views/dashboards/streams/registrant_replaced.turbo_stream.erb @@ -0,0 +1,3 @@ +<%= turbo_stream.update "registrant_banner", + partial: 'registrant/shared/banner', + locals: { message: message } %> diff --git a/app/views/registrant/domains/_domain.html.erb b/app/views/registrant/domains/_domain.html.erb new file mode 100644 index 0000000..3a67c2d --- /dev/null +++ b/app/views/registrant/domains/_domain.html.erb @@ -0,0 +1,24 @@ +
- test-domain1.ee
-
|
- Oleg Hasjanov | -- Active - | -<%= l(Time.zone.now + 1.year) %> | -- <%= link_to t('.renew'), '#', class: "px-3 py-1 rounded-md text-white bg-green-400 hover:bg-green-500 cursor-pointer", target: '_top' %> - - <%= link_to t('.show'), '#', class: "px-3 py-1 rounded-md text-white bg-yellow-400 hover:bg-yellow-500 cursor-pointer", target: '_top' %> - - <%= link_to t('.edit'), '#', class: "px-3 py-1 rounded-md text-white bg-blue-400 hover:bg-blue-500 cursor-pointer", target: '_top' %> - - <%= button_to t('.delete'), '#', method: :delete, class: "px-3 py-1 rounded-md text-white bg-red-400 hover:bg-red-500 cursor-pointer", form: { data: { turbo_confirm: t(".confirm_delete") } } %> - | -
Personal details and application.
+<%= key %>: <%= value %>
+ <% end %> +<%= key %>: <%= value %>
+ <% end %> +