diff --git a/.codeclimate.yml b/.codeclimate.yml index cdba2d7d7..2bc90b200 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -23,12 +23,15 @@ plugins: rubocop: enabled: true channel: rubocop-0-74 +checks: + method-lines: + config: + threshold: 40 exclude_patterns: - "app/models/version/" - "bin/" - "config/" - "db/" - - "lib/action_controller/" - "lib/core_monkey_patches/" - "lib/daemons/" - "lib/gem_monkey_patches/" diff --git a/.ruby-version b/.ruby-version index e30309f73..57cf282eb 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.7 +2.6.5 diff --git a/.travis.yml b/.travis.yml index 460122e12..bb74deecc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,7 @@ language: ruby -rvm: - - 2.4 - - 2.5 cache: bundler env: - DB=postgresql -bundler_args: --without development staging production before_install: - "wget -N http://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip -P ~/" - "unzip ~/chromedriver_linux64.zip -d ~/" @@ -13,19 +9,26 @@ before_install: - "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" - - "gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true" - - "gem install bundler -v '< 2'" + - "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" + - "bundle exec rake data:migrate" - "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" -script: - - "bundle exec rake test" after_script: - "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT" +script: + - "bundle exec rails test test/*" services: - postgresql addons: diff --git a/CHANGELOG.md b/CHANGELOG.md index 891372997..e8045349b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,259 @@ +14.08.2020 +* Added handling of second lvl zoness managed by the registry in whois records [#1661](https://github.com/internetee/registry/issues/1661) + +13.08.2020 +* Removed keystore gem and replaced LHV JKS with PKCS12 [#1645](https://github.com/internetee/registry/issues/1645) + +11.08.2020 +* Fixed postal address saving bug with disabled address processing [#1650](https://github.com/internetee/registry/issues/1650) + +07.08.2020 +* Restored creator and updator strings to contacts and related object records [#1636](https://github.com/internetee/registry/issues/1636) +* Security gem updates: sdoc to 1.1 and json to 2.3.1 [#1657](https://github.com/internetee/registry/pull/1657) + +04.08.2020 +* Fixed registrant verification for domain delete [#1631](https://github.com/internetee/registry/issues/1631) +* Fixed domain transfer issue when one person was present in the same role more than once (different objects) [#1651](https://github.com/internetee/registry/issues/1651) + +03.08.2020 +* Fixed 0 vat issue with invoices sent to Directo [#1647](https://github.com/internetee/registry/issues/1647) + +17.07.2020 +* Added turemail gem for validating email addresses syntactically and on MX record level [#297](https://github.com/internetee/registry/issues/297) + +15.07.2020 +* Reapplied race condition fix after fixing the data in prod env [#1612](https://github.com/internetee/registry/issues/1612) + +07.07.2020 +* Fixed legaldoc validation [#1634](https://github.com/internetee/registry/issues/1634) +* Disabled collection cashe versioning [#1637](https://github.com/internetee/registry/pull/1637) + +03.07.2020 +* 1-character domains are now valid but blocked by default [#1625](https://github.com/internetee/registry/issues/1625) + +02.07.2020 +* Adding legaldoc to domain:delete is now optional [#1624](https://github.com/internetee/registry/issues/1624) +* Setting to make legaldoc functionality optional [#1623](https://github.com/internetee/registry/issues/1623) + +01.07.2020 +* Reverted race condition fix due to data issues in production (#1612) [#1622](https://github.com/internetee/registry/pull/1622) +* Added legaldoc opt-out option for approved registrars [#1620](https://github.com/internetee/registry/issues/1620) + +29.06.2020 +* Bumped rack to 2.2.3 [#1618](https://github.com/internetee/registry/pull/1618) +* Actionpack security update to 6.0.3.2 [#1619](https://github.com/internetee/registry/pull/1619) + +26.06.2020 +* Fixed race condition in domain update by adding new db constratints [#1612](https://github.com/internetee/registry/issues/1612) +* Refactored contact validation [#1617](https://github.com/internetee/registry/pull/1617) + +19.06.2020 +* Regsitrant API returns now DNSSEC info [#1613](https://github.com/internetee/registry/pull/1613) +* Updated domain expiration email notification texts [#1614](https://github.com/internetee/registry/pull/1614) + +15.06.2020 +* Added contact email to registrant API [#1611](https://github.com/internetee/registry/pull/1611) + +12.06.2020 +* Extracted Xml deserializing from EPP Contact and Domain classes [#1601](https://github.com/internetee/registry/pull/1601) +* Fixed whois data update issue with child object updates [#1604](https://github.com/internetee/registry/issues/1604) + +11.06.2020 +* Auction API returns json on error [#1605](https://github.com/internetee/registry/issues/1605) +* Fixed account activity index in admin [#1606](https://github.com/internetee/registry/issues/1606) + +08.06.2020 +* Bumped websocket-extensions to 0.1.5 [#1602](https://github.com/internetee/registry/pull/1602) + +04.06.2020 +* Moved dev config to sample file [#1599](https://github.com/internetee/registry/pull/1599) +* Post Rails6 upgrade fixes [#1598](https://github.com/internetee/registry/pull/1598) + +03.06.2020 +* Upgraded Rails to 6.0.3 [#1593](https://github.com/internetee/registry/pull/1593) + +02.06.2020 +* Fixed registration deadline format for whois/restwhois [#1595](https://github.com/internetee/registry/pull/1595) + +01.06.2020 +* Improved error handling in case legal doc is not found for downloading [#1452](https://github.com/internetee/registry/issues/1452) + +29.05.2020 +* Bump kaminari to 1.2.1 [#1592](https://github.com/internetee/registry/pull/1592) + +28.05.2020 +* REPP returns list of disputed domains [#1588](https://github.com/internetee/registry/issues/1588) +* Updated Directo gem [#1590](https://github.com/internetee/registry/pull/1590) +* Updated LHV gem [#1591](https://github.com/internetee/registry/pull/1591) + +25.05.2020 +* Fixed registrant change verification bug for disputed domains [#1586](https://github.com/internetee/registry/issues/1586) + +22.05.2020 +* New solution for managing domains with effective dispute commitee decision [#269](https://github.com/internetee/registry/issues/269) +* Bump puma from 4.3.5 [#1585](https://github.com/internetee/registry/pull/1585) +* Run all CI tests [#1584](https://github.com/internetee/registry/pull/1584) + +21.05.2020 +* Fixed contact view access bug in registrant [#1527](https://github.com/internetee/registry/pull/1527) +* REPP returns list of domains currently at auction [#1582](https://github.com/internetee/registry/pull/1582) + +18.05.2020 +* REPP returns list of reserved and blocked domains [#1569](https://github.com/internetee/registry/issues/1569) + +14.05.2020 +* Deleted certificates are now revoked first [#952](https://github.com/internetee/registry/issues/952) + +11.05.2020 +* Auction process due dates are now available over whois and rest-whois [#1201](https://github.com/internetee/registry/issues/1201) + +30.04.2020 +* Fix for internal error on opening domain history with legacy id record [#1576](https://github.com/internetee/registry/issues/1576) + +27.04.2020 +* Downgrade SimpleCov to 0.17 due to incompatibiilty with CodeClimate [#1575](https://github.com/internetee/registry/pull/1575) + +17.04.2020 +* Webinterfaces have now clickable version string pointing to the latest deployed commit in github [#1345](https://github.com/internetee/registry/pull/1345) + +15.04.2020 +* Updated Rails to 5.2 and fixed acitionview security issue [#1568](https://github.com/internetee/registry/issues/1568) + +25.03.2020 +* Implemented Directo gem [#1547](https://github.com/internetee/registry/pull/1547) + +11.03.2020 +* Fixed glue record issues when using 2nd level domain as host [#1562](https://github.com/internetee/registry/issues/1562) + +10.03.2020 +* Updated lhv, e-invoice & company_register gem due to security updates [#1564](https://github.com/internetee/registry/pull/1564) + +06.03.2020 +* Record payment method and failed payments [#1422](https://github.com/internetee/registry/issues/1422) + +04.03.2020 +* Bump Puma to 4.3.3 [#1557](https://github.com/internetee/registry/pull/1557) + +03.03.2020 +* Admin: fixed import of th6 bank statement [#1551](https://github.com/internetee/registry/issues/1551) + +02.03.2020 +* Registrar: fixed statuses based contact filtering [#1004](https://github.com/internetee/registry/issues/1004) + +28.02.2020 +* Registrar: fixed account switching [#1535](https://github.com/internetee/registry/issues/1535) + +27.02.2020 +* Registrar: fixed the verified checkbox bug that did not change the element value to yes in epp request [#1540](https://github.com/internetee/registry/issues/1540) +* Ruby version update to 2.6.5 [#1545](https://github.com/internetee/registry/pull/1545) + +26.02.2020 +* Registrar: added an option to remove clientHold status [#1481](https://github.com/internetee/registry/issues/1481) +* Admin: fixed domain status removal issue [#1543](https://github.com/internetee/registry/issues/1543) +* Implemented consistent and automated data migrations [#1298](https://github.com/internetee/registry/issues/1298) + +20.02.2020 +* E-invoice sending to Que to manage resending in case of an error [#1509](https://github.com/internetee/registry/issues/1509) +* Check to make sure all monthly invoices fit in available invoice number range [#277](https://github.com/internetee/registry/issues/277) +* Disabled aurbreak performance monitoring [#1534](https://github.com/internetee/registry/pull/1534) + +14.02.2020 +* Fixed Papertrail warnings [#1530](https://github.com/internetee/registry/issues/1530) + +12.02.2020 +* Fixed papertrails double recording issue [#1526](https://github.com/internetee/registry/issues/1526) +* Requests to Directo are now saved for both credit and monthly invoices [#344](https://github.com/internetee/registry/issues/344) + +10.02.2020 +* Resolved Money gem deprecation warning and silenced all warnings due plan to replace papertrail [#1522](https://github.com/internetee/registry/pull/1522) + +06.02.2020 +* Permit & turn ActiveController::Parameters to hash on domain create [#1516](https://github.com/internetee/registry/issues/1516) + +05.02.2020 +* Ruby version upgrade to 2.6.3 [#846](https://github.com/internetee/registry/issues/846) +* Added retries & raise to connect api to handle timeouts [#1474](https://github.com/internetee/registry/issues/1474) +* Added logging of XML if there is NoMethodError#text on xml data fields [#1475](https://github.com/internetee/registry/issues/1475) + +04.02.2020 +* Fixed bug that allowed bypassing blocked domain validation using punycode [#1142](https://github.com/internetee/registry/issues/1142) +* SimpleIDN gem update to 0.0.9 [#1508](https://github.com/internetee/registry/pull/1508) + +31.01.2020 +* Instant payments marks specific invoice as paid [#1500](https://github.com/internetee/registry/issues/1500) +* Sending invoice payment date to accounting [#1416](https://github.com/internetee/registry/issues/1416) + +29.01.2020 +* Fixed the invoice binding bug where process failed if registrar tried to load a sum that they have used before [#1496](https://github.com/internetee/registry/issues/1496) + +28.01.2020 +* Registrar: fixed sorting of domain view [#1461](https://github.com/internetee/registry/issues/1461) +* clientHold status is now set once instead of resetting it every time the job is run [#1480](https://github.com/internetee/registry/issues/1480) + +27.01.2020 +* Admin: fixed history view for domains with legacy id [#1489](https://github.com/internetee/registry/issues/1489) + +23.01.2020 +* Payment invoice matching by looking for ref nr in description field [#1415](https://github.com/internetee/registry/issues/1415) + +22.01.2020 +* ForceDelete poll messages with outzone and purge dates [#1478](https://github.com/internetee/registry/issues/1478) + +21.01.2020 +* Registrant change cancels automatically force delete process [#1479](https://github.com/internetee/registry/issues/1479) + +20.01.2020 +* ForceDelete email notifications are sent to all contacts + info and domain@domain [#1477](https://github.com/internetee/registry/issues/1477) + +18.01.2020 +* New ForceDelete procedure [#1428](https://github.com/internetee/registry/issues/1428) + +16.01.2020 +* Added tests for registrant verification [#1430](https://github.com/internetee/registry/pull/1430) + +14.01.2020 +* removed authinfo element from contact:info response for non-sponsoring registrars [#1446](https://github.com/internetee/registry/issues/1446) + +13.01.2020 +* resolved internal error on registrant confirmation [#1468](https://github.com/internetee/registry/issues/1468) + +10.01.2020 +* updated ForceDelete email templates according new regulation [#1466](https://github.com/internetee/registry/issues/1466) +* regenerated WHOIS db schema [#1436](https://github.com/internetee/registry/pull/1436) + +09.01.2020 +* serverForceDelete status does not block removing clientHold status [#1462](https://github.com/internetee/registry/pull/1462) + +06.01.2020 +* Updated e-invoice gem [#1456](https://github.com/internetee/registry/pull/1456) +* Bumped rack gem to 2.0.8 [#1448](https://github.com/internetee/registry/pull/1448) + +03.01.2020 +* Added an option for registrars to add and remove clientHold status on domains [#1454](https://github.com/internetee/registry/pull/1454) +* Fixed contact view internal error in admin [#1458](https://github.com/internetee/registry/issues/1458) + +27.12.2019 +* Records in registrant_verifications are now archived by PaperTrail [#1425](https://github.com/internetee/registry/issues/1425) + +16.12.2019 +* Bump puma from 4.2.1 to 4.3.1 [#1437](https://github.com/internetee/registry/pull/1437) +* Refactored API user management [#1435](https://github.com/internetee/registry/pull/1435) +* Ignoring legacy database columns at ActiveRecord level [#1377](https://github.com/internetee/registry/issues/1377) +* Removed Ruby version from Travis config and let it use .ruby-version [#1441](https://github.com/internetee/registry/pull/1441) +* Removed `fill_ident_country` postgresql function as unused [#1439](https://github.com/internetee/registry/pull/1439) + +12.12.2019 +* Updated e-invoice gem [#1429](https://github.com/internetee/registry/pull/1429) +* Upgraded bundler to 2.0.2 [#1433](https://github.com/internetee/registry/pull/1433) +* Set not null constraint on contact.name db column [#1417](https://github.com/internetee/registry/pull/1417) +* Removed domain name from registrant_verifications table [#1431](https://github.com/internetee/registry/pull/1431) + +19.11.2019 +* Updated Rails to 5.0.7 [#377](https://github.com/internetee/registry/issues/377) + +15.11.2019 +* Restored EPP exception logging to syslog [#1371](https://github.com/internetee/registry/issues/1371) + 11.11.2019 * Removed code for displaying errors in nameserver and dnskey data as unused [#1411](https://github.com/internetee/registry/pull/1411) diff --git a/Dockerfile b/Dockerfile index 7e3b11d80..5d241eeef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM internetee/ruby:2.4 +FROM internetee/ruby:2.6-buster RUN mkdir -p /opt/webapps/app/tmp/pids WORKDIR /opt/webapps/app diff --git a/Gemfile b/Gemfile index 948d1185a..7ad72f5fa 100644 --- a/Gemfile +++ b/Gemfile @@ -1,15 +1,9 @@ -# Use https only for accessing github -# https://github.com/bundler/bundler/pull/3447 -git_source(:github) do |repo_name| - repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") - "https://github.com/#{repo_name}.git" -end if Bundler::VERSION < '2' - source 'https://rubygems.org' # core -gem 'iso8601', '0.8.6' # for dates and times -gem 'rails', '4.2.11.1' # when update, all initializers eis_custom files needs check/update +gem 'bootsnap', '>= 1.1.0', require: false +gem 'iso8601', '0.12.1' # for dates and times +gem 'rails', '~> 6.0' gem 'rest-client' gem 'uglifier' @@ -17,11 +11,13 @@ gem 'uglifier' gem 'figaro', '1.1.1' # model related -gem 'pg', '0.19.0' +gem 'activerecord-import' +gem 'paper_trail', '~> 10.3' +gem 'pg', '1.2.2' # 1.8 is for Rails < 5.0 -gem 'ransack', '~> 1.8' +gem 'ransack', '~> 2.3' +gem 'truemail', '~> 1.7' # validates email by regexp, mail server existence and address existence gem 'validates_email_format_of', '1.6.3' # validates email against RFC 2822 and RFC 3696 -gem 'paper_trail', '~> 4.0' # 0.7.3 is the latest for Rails 4.2, however, it is absent on Rubygems server # https://github.com/huacnlee/rails-settings-cached/issues/165 @@ -30,12 +26,12 @@ gem 'nokogiri' # style gem 'bootstrap-sass', '~> 3.4' -gem 'sass-rails', '5.0.6' # sass style -gem 'coffee-rails', '~> 4.2' +gem 'coffee-rails', '>= 5.0' gem 'jquery-rails' gem 'selectize-rails', '0.12.1' # include selectize.js for select gem 'kaminari' gem 'coderay', '1.1.0' # xml console visualize +gem 'sass-rails' gem 'select2-rails', '3.5.9.3' # for autocomplete gem 'cancancan' gem 'devise', '~> 4.7' @@ -43,10 +39,10 @@ gem 'devise', '~> 4.7' gem 'grape' # registry specfic +gem 'data_migrate', '~> 6.1' gem 'isikukood' # for EE-id validation -gem 'simpleidn', '0.0.7' # For punycode +gem 'simpleidn', '0.1.1' # For punycode gem 'money-rails' -gem 'data_migrate' gem 'whenever', '0.9.4', require: false # country listing @@ -66,34 +62,36 @@ gem 'daemons-rails', '1.2.1' gem 'que-web' gem 'pdfkit' gem 'jquery-ui-rails', '5.0.5' -gem 'active_model-errors_details' # Backport from Rails 5, https://github.com/rails/rails/pull/18322 gem 'airbrake' gem 'company_register', github: 'internetee/company_register', branch: :master gem 'e_invoice', github: 'internetee/e_invoice', branch: :master -gem 'lhv', github: 'internetee/lhv', tag: 'v0.1.0' +gem 'lhv', github: 'internetee/lhv', branch: 'master' gem 'domain_name' gem 'haml', '~> 5.0' -gem 'wkhtmltopdf-binary' +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' - gem 'sdoc', '0.4.1' # bundle exec rake doc:rails generates the API under doc/api. gem 'railroady', '1.3.0' # to generate database diagrams gem 'autodoc' gem 'puma' + gem 'sdoc', '~> 1.1' end group :test do gem 'capybara' gem 'database_cleaner' - gem 'simplecov', require: false + gem 'minitest', '~> 5.14' + gem 'simplecov', '0.17.1', require: false # CC last supported v0.17 gem 'webdrivers' gem 'webmock' - gem 'minitest', '~> 5.10.0' end diff --git a/Gemfile.lock b/Gemfile.lock index 9445b7f3d..7b18612e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,15 +1,24 @@ GIT remote: https://github.com/internetee/company_register.git - revision: da7130542304fc543c90d54cd037d019a777c526 + revision: 86d691997aa7def9f86d88f6c92cabb86cd65487 branch: master specs: company_register (0.1.0) activesupport savon +GIT + remote: https://github.com/internetee/directo.git + revision: 8ff8a382d004ffb85722a6a7a68a020bd4d7159b + branch: master + specs: + directo (1.0.1) + money (~> 6.13) + nokogiri (~> 1.10) + GIT remote: https://github.com/internetee/e_invoice.git - revision: 917318bd546322408b83567745375c998619c926 + revision: b374ffd7be77b559b30c7a0210dc0df5ac3ed723 branch: master specs: e_invoice (0.1.0) @@ -19,15 +28,15 @@ GIT GIT remote: https://github.com/internetee/epp-xml.git - revision: 5dd542e67ef26d58365f30e553254d6db809277d + revision: 27959f8cb244ea5eabaeeee747984988b454e840 specs: epp-xml (1.1.0) - activesupport (~> 4.1) + activesupport (>= 4.1) builder (~> 3.2) GIT remote: https://github.com/internetee/epp.git - revision: 76f9fd487d0ca3865b6f706c5a72703951c03996 + revision: af7cefda37ac81d14b1d12641cde410776082d59 branch: master specs: epp (1.5.0) @@ -36,11 +45,11 @@ GIT GIT remote: https://github.com/internetee/lhv.git - revision: e211516bc5fff2139584d4da41c17511863c229d - tag: v0.1.0 + revision: 1825240b3bf8b262418cc6c8ef7ed1aba386dd7d + branch: master specs: lhv (0.1.0) - keystores + logger nokogiri GIT @@ -58,70 +67,87 @@ GIT GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.11.1) - actionpack (= 4.2.11.1) - actionview (= 4.2.11.1) - activejob (= 4.2.11.1) + actioncable (6.0.3.2) + actionpack (= 6.0.3.2) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.0.3.2) + actionpack (= 6.0.3.2) + activejob (= 6.0.3.2) + activerecord (= 6.0.3.2) + activestorage (= 6.0.3.2) + activesupport (= 6.0.3.2) + mail (>= 2.7.1) + actionmailer (6.0.3.2) + actionpack (= 6.0.3.2) + actionview (= 6.0.3.2) + activejob (= 6.0.3.2) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.11.1) - actionview (= 4.2.11.1) - activesupport (= 4.2.11.1) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.11.1) - activesupport (= 4.2.11.1) + rails-dom-testing (~> 2.0) + actionpack (6.0.3.2) + actionview (= 6.0.3.2) + activesupport (= 6.0.3.2) + rack (~> 2.0, >= 2.0.8) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.0.3.2) + actionpack (= 6.0.3.2) + activerecord (= 6.0.3.2) + activestorage (= 6.0.3.2) + activesupport (= 6.0.3.2) + nokogiri (>= 1.8.5) + actionview (6.0.3.2) + activesupport (= 6.0.3.2) builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - active_model-errors_details (1.3.1) - activemodel (>= 3.2.13, < 5.0.0) - activesupport - activejob (4.2.11.1) - activesupport (= 4.2.11.1) - globalid (>= 0.3.0) - activemodel (4.2.11.1) - activesupport (= 4.2.11.1) - builder (~> 3.1) - activerecord (4.2.11.1) - activemodel (= 4.2.11.1) - activesupport (= 4.2.11.1) - arel (~> 6.0) - activesupport (4.2.11.1) - i18n (~> 0.7) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.0.3.2) + activesupport (= 6.0.3.2) + globalid (>= 0.3.6) + activemodel (6.0.3.2) + activesupport (= 6.0.3.2) + activerecord (6.0.3.2) + activemodel (= 6.0.3.2) + activesupport (= 6.0.3.2) + activerecord-import (1.0.5) + activerecord (>= 3.2) + activestorage (6.0.3.2) + actionpack (= 6.0.3.2) + activejob (= 6.0.3.2) + activerecord (= 6.0.3.2) + marcel (~> 0.3.1) + activesupport (6.0.3.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) + zeitwerk (~> 2.2, >= 2.2.2) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - airbrake (9.4.3) - airbrake-ruby (~> 4.6) - airbrake-ruby (4.6.0) + airbrake (10.0.5) + airbrake-ruby (~> 4.13) + airbrake-ruby (4.15.0) rbtree3 (~> 0.5) akami (1.3.1) gyoku (>= 0.4.0) nokogiri - arel (6.0.4) - autodoc (0.6.0) + autodoc (0.7.4) actionpack activesupport (>= 3.0.0) rspec - autoprefixer-rails (9.4.8) + autoprefixer-rails (9.8.4) execjs - axiom-types (0.1.1) - descendants_tracker (~> 0.0.4) - ice_nine (~> 0.11.0) - thread_safe (~> 0.3, >= 0.3.1) bcrypt (3.1.13) + bootsnap (1.4.6) + msgpack (~> 1.0) bootstrap-sass (3.4.1) autoprefixer-rails (>= 5.2.1) sassc (>= 2.0.0) - builder (3.2.3) - cancancan (3.0.1) - capybara (3.29.0) + builder (3.2.4) + cancancan (3.1.0) + capybara (3.33.0) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) @@ -132,228 +158,262 @@ GEM childprocess (3.0.0) chronic (0.10.2) coderay (1.1.0) - coercible (1.0.0) - descendants_tracker (~> 0.0.1) - coffee-rails (4.2.2) + coffee-rails (5.0.0) coffee-script (>= 2.2.0) - railties (>= 4.0.0) + railties (>= 5.2.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.5) - countries (3.0.0) - i18n_data (~> 0.8.0) + concurrent-ruby (1.1.6) + countries (3.0.1) + i18n_data (~> 0.10.0) sixarm_ruby_unaccent (~> 1.1) unicode_utils (~> 1.4) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.5) - daemons (1.2.4) + crass (1.0.6) + daemons (1.3.1) daemons-rails (1.2.1) daemons multi_json (~> 1.0) - data_migrate (5.3.2) - rails (>= 4.2) - database_cleaner (1.6.1) - descendants_tracker (0.0.4) - thread_safe (~> 0.3, >= 0.3.1) - devise (4.7.1) + data_migrate (6.3.0) + rails (>= 5.0) + database_cleaner (1.8.5) + devise (4.7.2) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) - diff-lcs (1.3) + diff-lcs (1.4.4) docile (1.3.2) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - equalizer (0.0.11) + dry-configurable (0.11.6) + concurrent-ruby (~> 1.0) + dry-core (~> 0.4, >= 0.4.7) + dry-equalizer (~> 0.2) + dry-container (0.7.2) + concurrent-ruby (~> 1.0) + dry-configurable (~> 0.1, >= 0.1.3) + dry-core (0.4.9) + concurrent-ruby (~> 1.0) + dry-equalizer (0.3.0) + dry-inflector (0.2.0) + dry-logic (1.0.6) + concurrent-ruby (~> 1.0) + dry-core (~> 0.2) + dry-equalizer (~> 0.2) + dry-types (1.4.0) + concurrent-ruby (~> 1.0) + dry-container (~> 0.3) + dry-core (~> 0.4, >= 0.4.4) + dry-equalizer (~> 0.3) + dry-inflector (~> 0.1, >= 0.1.2) + dry-logic (~> 1.0, >= 1.0.2) + erubi (1.9.0) erubis (2.7.0) execjs (2.7.0) - ffi (1.9.25) + ffi (1.13.1) figaro (1.1.1) thor (~> 0.14) globalid (0.4.2) activesupport (>= 4.2.0) - grape (1.2.3) + grape (1.3.3) activesupport builder + dry-types (>= 1.1) mustermann-grape (~> 1.0.0) rack (>= 1.3.0) rack-accept - virtus (>= 1.0.0) gyoku (1.3.1) builder (>= 2.1.2) haml (5.1.2) temple (>= 0.8.0) tilt - hashdiff (1.0.0) + hashdiff (1.0.1) hpricot (0.8.6) + http-accept (1.7.0) http-cookie (1.0.3) domain_name (~> 0.5) httpclient (2.8.3) httpi (2.4.4) rack socksify - i18n (0.9.5) + i18n (1.8.3) concurrent-ruby (~> 1.0) - i18n_data (0.8.0) - ice_nine (0.11.2) + i18n_data (0.10.0) isikukood (0.1.2) - iso8601 (0.8.6) - jquery-rails (4.3.5) + iso8601 (0.12.1) + jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) jquery-ui-rails (5.0.5) railties (>= 3.2.16) - json (1.8.6) - kaminari (1.1.1) + json (2.3.1) + kaminari (1.2.1) activesupport (>= 4.1.0) - kaminari-actionview (= 1.1.1) - kaminari-activerecord (= 1.1.1) - kaminari-core (= 1.1.1) - kaminari-actionview (1.1.1) + kaminari-actionview (= 1.2.1) + kaminari-activerecord (= 1.2.1) + kaminari-core (= 1.2.1) + kaminari-actionview (1.2.1) actionview - kaminari-core (= 1.1.1) - kaminari-activerecord (1.1.1) + kaminari-core (= 1.2.1) + kaminari-activerecord (1.2.1) activerecord - kaminari-core (= 1.1.1) - kaminari-core (1.1.1) - keystores (0.4.0) - libxml-ruby (3.1.0) - loofah (2.3.1) + 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.6.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) + marcel (0.3.3) + mimemagic (~> 0.3.2) method_source (0.8.2) - mime-types (3.1) + mime-types (3.3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) + 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.10.3) - monetize (1.9.0) + minitest (5.14.1) + monetize (1.9.4) money (~> 6.12) - money (6.12.0) - i18n (>= 0.6.4, < 1.1) - money-rails (1.12.0) + money (6.13.8) + i18n (>= 0.6.4, <= 2) + money-rails (1.13.3) activesupport (>= 3.0) monetize (~> 1.9.0) - money (~> 6.12.0) + money (~> 6.13.2) railties (>= 3.0) - multi_json (1.13.1) - mustermann (1.0.3) - mustermann-grape (1.0.0) - mustermann (~> 1.0.0) + msgpack (1.3.3) + multi_json (1.14.1) + mustermann (1.1.1) + ruby2_keywords (~> 0.0.1) + mustermann-grape (1.0.1) + mustermann (>= 1.0.0) netrc (0.11.0) nio4r (2.5.2) - nokogiri (1.10.4) + nokogiri (1.10.10) mini_portile2 (~> 2.4.0) nori (2.6.0) open4 (1.3.4) orm_adapter (0.5.0) - paper_trail (4.2.0) - activerecord (>= 3.0, < 6.0) - activesupport (>= 3.0, < 6.0) + paper_trail (10.3.1) + activerecord (>= 4.2) request_store (~> 1.1) - pdfkit (0.8.4.1) - pg (0.19.0) + pdfkit (0.8.4.3.1) + pg (1.2.2) + polyamorous (2.3.2) + activerecord (>= 5.2.1) pry (0.10.1) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - public_suffix (4.0.1) - puma (4.2.1) + public_suffix (4.0.5) + puma (4.3.5) nio4r (~> 2.0) que (0.14.3) que-web (0.7.2) erubis que (~> 0.8) sinatra - rack (1.6.11) + rack (2.2.3) rack-accept (0.4.5) rack (>= 0.4) - rack-protection (1.5.5) + rack-protection (2.0.8.1) rack - rack-test (0.6.3) - rack (>= 1.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) railroady (1.3.0) - rails (4.2.11.1) - actionmailer (= 4.2.11.1) - actionpack (= 4.2.11.1) - actionview (= 4.2.11.1) - activejob (= 4.2.11.1) - activemodel (= 4.2.11.1) - activerecord (= 4.2.11.1) - activesupport (= 4.2.11.1) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.11.1) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.9) - activesupport (>= 4.2.0, < 5.0) - nokogiri (~> 1.6) - rails-deprecated_sanitizer (>= 1.0.1) + rails (6.0.3.2) + actioncable (= 6.0.3.2) + actionmailbox (= 6.0.3.2) + actionmailer (= 6.0.3.2) + actionpack (= 6.0.3.2) + actiontext (= 6.0.3.2) + actionview (= 6.0.3.2) + activejob (= 6.0.3.2) + activemodel (= 6.0.3.2) + activerecord (= 6.0.3.2) + activestorage (= 6.0.3.2) + activesupport (= 6.0.3.2) + bundler (>= 1.3.0) + railties (= 6.0.3.2) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) rails-settings-cached (0.7.2) rails (>= 4.2.0) - railties (4.2.11.1) - actionpack (= 4.2.11.1) - activesupport (= 4.2.11.1) + railties (6.0.3.2) + actionpack (= 6.0.3.2) + activesupport (= 6.0.3.2) + method_source rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (12.3.3) - ransack (1.8.10) - actionpack (>= 3.0, < 5.2) - activerecord (>= 3.0, < 5.2) - activesupport (>= 3.0, < 5.2) + thor (>= 0.20.3, < 2.0) + rake (13.0.1) + ransack (2.3.2) + activerecord (>= 5.2.1) + activesupport (>= 5.2.1) i18n - rbtree3 (0.5.0) - rdoc (4.3.0) - regexp_parser (1.6.0) - request_store (1.4.1) + polyamorous (= 2.3.2) + rb-fsevent (0.10.4) + rb-inotify (0.10.1) + ffi (~> 1.0) + rbtree3 (0.6.0) + rdoc (6.2.1) + regexp_parser (1.7.1) + request_store (1.5.0) rack (>= 1.4) - responders (2.4.1) - actionpack (>= 4.2.0, < 6.0) - railties (>= 4.2.0, < 6.0) - rest-client (2.0.1) + responders (3.0.1) + actionpack (>= 5.0) + railties (>= 5.0) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - rspec (3.6.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-core (3.9.2) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-mocks (3.6.0) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-support (3.6.0) - rubyzip (2.0.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.3) + ruby2_keywords (0.0.2) + rubyzip (2.3.0) safe_yaml (1.0.5) - sass (3.4.23) - sass-rails (5.0.6) - railties (>= 4.0.0, < 6) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (>= 1.1, < 3) - sassc (2.0.0) - ffi (~> 1.9.6) - rake - savon (2.12.0) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + savon (2.12.1) akami (~> 1.2) builder (>= 2.1.2) gyoku (~> 1.2) @@ -361,13 +421,12 @@ GEM nokogiri (>= 1.8.1) nori (~> 2.4) wasabi (~> 3.4) - sdoc (0.4.1) - json (~> 1.7, >= 1.7.7) - rdoc (~> 4.0) + sdoc (1.1.0) + rdoc (>= 5.0) select2-rails (3.5.9.3) thor (~> 0.14) selectize-rails (0.12.1) - selenium-webdriver (3.142.6) + selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) simplecov (0.17.1) @@ -375,15 +434,17 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) - simpleidn (0.0.7) - sinatra (1.4.8) - rack (~> 1.5) - rack-protection (~> 1.4) - tilt (>= 1.3, < 3) + simpleidn (0.1.1) + unf (~> 0.1.4) + sinatra (2.0.8.1) + mustermann (~> 1.0) + rack (~> 2.0) + rack-protection (= 2.0.8.1) + tilt (~> 2.0) sixarm_ruby_unaccent (1.2.0) slop (3.6.0) socksify (1.7.1) - sprockets (3.7.2) + sprockets (4.0.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.1) @@ -394,59 +455,62 @@ GEM thor (0.20.3) thread_safe (0.3.6) tilt (2.0.10) - tzinfo (1.2.5) + truemail (1.8.0) + simpleidn (~> 0.1.1) + tzinfo (1.2.7) thread_safe (~> 0.1) - uglifier (4.1.11) + uglifier (4.2.0) execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext - unf_ext (0.0.7.6) + unf_ext (0.0.7.7) unicode_utils (1.4.0) validates_email_format_of (1.6.3) i18n - virtus (1.0.5) - axiom-types (~> 0.1) - coercible (~> 1.0) - descendants_tracker (~> 0.0, >= 0.0.3) - equalizer (~> 0.0, >= 0.0.9) - warden (1.2.7) - rack (>= 1.0) + warden (1.2.8) + rack (>= 2.0.6) wasabi (3.5.0) httpi (~> 2.0) nokogiri (>= 1.4.2) - webdrivers (4.1.3) + webdrivers (4.4.1) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (>= 3.0, < 4.0) - webmock (3.7.6) + webmock (3.8.3) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) + websocket-driver (0.7.2) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) whenever (0.9.4) chronic (>= 0.6.3) - wkhtmltopdf-binary (0.12.4) + wkhtmltopdf-binary (0.12.5.4) xpath (3.2.0) nokogiri (~> 1.8) + zeitwerk (2.3.1) PLATFORMS ruby DEPENDENCIES - active_model-errors_details + activerecord-import airbrake autodoc + bootsnap (>= 1.1.0) bootstrap-sass (~> 3.4) cancancan capybara coderay (= 1.1.0) - coffee-rails (~> 4.2) + coffee-rails (>= 5.0) company_register! countries daemons-rails (= 1.2.1) - data_migrate + data_migrate (~> 6.1) database_cleaner devise (~> 4.7) digidoc_client! + directo! domain_name e_invoice! epp! @@ -455,39 +519,41 @@ DEPENDENCIES grape haml (~> 5.0) isikukood - iso8601 (= 0.8.6) + iso8601 (= 0.12.1) jquery-rails jquery-ui-rails (= 5.0.5) kaminari lhv! + listen (= 3.2.1) mina (= 0.3.1) - minitest (~> 5.10.0) + minitest (~> 5.14) money-rails nokogiri - paper_trail (~> 4.0) + paper_trail (~> 10.3) pdfkit - pg (= 0.19.0) + pg (= 1.2.2) pry (= 0.10.1) puma que que-web railroady (= 1.3.0) - rails (= 4.2.11.1) + rails (~> 6.0) rails-settings-cached (= 0.7.2) - ransack (~> 1.8) + ransack (~> 2.3) rest-client - sass-rails (= 5.0.6) - sdoc (= 0.4.1) + sass-rails + sdoc (~> 1.1) select2-rails (= 3.5.9.3) selectize-rails (= 0.12.1) - simplecov - simpleidn (= 0.0.7) + simplecov (= 0.17.1) + simpleidn (= 0.1.1) + truemail (~> 1.7) uglifier validates_email_format_of (= 1.6.3) webdrivers webmock whenever (= 0.9.4) - wkhtmltopdf-binary + wkhtmltopdf-binary (~> 0.12.5.1) BUNDLED WITH - 1.17.3 + 2.1.4 diff --git a/Rakefile b/Rakefile index ba6b733dd..e85f91391 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require_relative 'config/application' Rails.application.load_tasks diff --git a/app/api/repp/api.rb b/app/api/repp/api.rb index e5bda46f5..af6864cfa 100644 --- a/app/api/repp/api.rb +++ b/app/api/repp/api.rb @@ -30,7 +30,8 @@ module Repp webclient_cert_name = ENV['webclient_cert_common_name'] || 'webclient' error! "Webclient #{message} #{webclient_cert_name}", 401 if webclient_cert_name != request_name else - unless @current_user.api_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) + unless @current_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], + request.env['HTTP_SSL_CLIENT_S_DN_CN']) error! "#{message} #{@current_user.username}", 401 end end diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 000000000..89c89e752 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ + //= link_tree ../images + //= link_directory ../javascripts .js + //= link_directory ../stylesheets .css diff --git a/app/assets/javascripts/admin/autocomplete.js.coffee b/app/assets/javascripts/admin/autocomplete.js.coffee index 84708055c..2308c1d28 100644 --- a/app/assets/javascripts/admin/autocomplete.js.coffee +++ b/app/assets/javascripts/admin/autocomplete.js.coffee @@ -47,12 +47,6 @@ class @Autocomplete selector: '.js-contact-typeahead' hiddenSelector: '.js-contact-id' - @bindAdminRegistrarSearch: -> - Autocomplete.bindTypeahead - remote: '/admin/registrars/search' - selector: '.js-registrar-typeahead' - hiddenSelector: '.js-registrar-id' - @bindClientContactSearch: -> Autocomplete.bindTypeahead remote: '/client/contacts/search' diff --git a/app/assets/stylesheets/shared/general.sass b/app/assets/stylesheets/shared/general.sass index 07b92cdbe..6d1c4956d 100644 --- a/app/assets/stylesheets/shared/general.sass +++ b/app/assets/stylesheets/shared/general.sass @@ -15,6 +15,9 @@ body > .container padding-top: 15px font-size: 10px +a.footer-version-link + color: black + .nowrap white-space: nowrap diff --git a/app/controllers/admin/account_activities_controller.rb b/app/controllers/admin/account_activities_controller.rb index 6a37e36dc..e022843ff 100644 --- a/app/controllers/admin/account_activities_controller.rb +++ b/app/controllers/admin/account_activities_controller.rb @@ -23,11 +23,11 @@ module Admin @q.sorts = 'id desc' if @q.sorts.empty? @account_activities = @q.result.page(params[:page]).per(params[:results_per_page]) - sort = @account_activities.orders.map(&:to_sql).join(",") - # can do here inline SQL as it's our if params[:page] && params[:page].to_i > 1 - @sum = @q.result.reorder(sort).limit(@account_activities.offset_value).sum(:sum) + @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) + @sum = @q.result.limit(@account_activities.offset_value).sum(:sum) + + @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})") + .sum(:sum) else @sum = @b.result.where("account_activities.id NOT IN (#{@q.result.select(:id).to_sql})").sum(:sum) end diff --git a/app/controllers/admin/api_users_controller.rb b/app/controllers/admin/api_users_controller.rb index bbf0a8a4e..8876c726f 100644 --- a/app/controllers/admin/api_users_controller.rb +++ b/app/controllers/admin/api_users_controller.rb @@ -1,7 +1,6 @@ module Admin class ApiUsersController < BaseController load_and_authorize_resource - before_action :set_api_user, only: [:show, :edit, :update, :destroy] def index @q = ApiUser.includes(:registrar).search(params[:q]) @@ -9,18 +8,17 @@ module Admin end def new - @registrar = Registrar.find_by(id: params[:registrar_id]) - @api_user = ApiUser.new(registrar: @registrar) + @api_user = registrar.api_users.build end def create - @api_user = ApiUser.new(api_user_params) + @api_user = registrar.api_users.build(api_user_params) - if @api_user.save - flash[:notice] = I18n.t('record_created') - redirect_to [:admin, @api_user] + if @api_user.valid? + @api_user.save! + redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user), + notice: t('.created') else - flash.now[:alert] = I18n.t('failed_to_create_record') render 'new' end end @@ -32,39 +30,31 @@ module Admin end def update - if params[:api_user][:plain_text_password].blank? - params[:api_user].delete(:plain_text_password) - end + @api_user.attributes = api_user_params - if @api_user.update(api_user_params) - flash[:notice] = I18n.t('record_updated') - redirect_to [:admin, @api_user] + if @api_user.valid? + @api_user.save! + redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user), + notice: t('.updated') else - flash.now[:alert] = I18n.t('failed_to_update_record') render 'edit' end end def destroy - if @api_user.destroy - flash[:notice] = I18n.t('record_deleted') - redirect_to admin_api_users_path - else - flash.now[:alert] = I18n.t('failed_to_delete_record') - render 'show' - end + @api_user.destroy! + redirect_to admin_registrar_path(@api_user.registrar), notice: t('.deleted') end private - def set_api_user - @api_user = ApiUser.find(params[:id]) - end - def api_user_params params.require(:api_user).permit(:username, :plain_text_password, :active, - :registrar_id, :registrar_typeahead, :identity_code, { roles: [] }) end + + def registrar + Registrar.find(params[:registrar_id]) + end end end diff --git a/app/controllers/admin/bank_statements_controller.rb b/app/controllers/admin/bank_statements_controller.rb index a70387317..1e3b31bf5 100644 --- a/app/controllers/admin/bank_statements_controller.rb +++ b/app/controllers/admin/bank_statements_controller.rb @@ -60,7 +60,7 @@ module Admin end def bind_invoices - @bank_statement.bind_invoices + @bank_statement.bind_invoices(manual: true) flash[:notice] = t('invoices_were_fully_binded') if @bank_statement.fully_binded? flash[:warning] = t('invoices_were_partially_binded') if @bank_statement.partially_binded? diff --git a/app/controllers/admin/bank_transactions_controller.rb b/app/controllers/admin/bank_transactions_controller.rb index 1ce62b279..348cadc64 100644 --- a/app/controllers/admin/bank_transactions_controller.rb +++ b/app/controllers/admin/bank_transactions_controller.rb @@ -34,7 +34,7 @@ module Admin end def bind - if @bank_transaction.bind_invoice(params[:invoice_no]) + if @bank_transaction.bind_invoice(params[:invoice_no], manual: true) flash[:notice] = I18n.t('record_created') redirect_to [:admin, @bank_transaction] else diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 17e75785a..1fec2a18f 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -2,6 +2,7 @@ module Admin class BaseController < ApplicationController before_action :authenticate_admin_user! helper_method :head_title_sufix + before_action :set_paper_trail_whodunnit def head_title_sufix t(:admin_head_title_sufix) @@ -17,4 +18,4 @@ module Admin current_admin_user ? current_admin_user.id_role_username : 'anonymous' end end -end \ No newline at end of file +end diff --git a/app/controllers/admin/certificates_controller.rb b/app/controllers/admin/certificates_controller.rb index 636a69367..d338b2e9f 100644 --- a/app/controllers/admin/certificates_controller.rb +++ b/app/controllers/admin/certificates_controller.rb @@ -34,7 +34,7 @@ module Admin if @certificate.destroy flash[:notice] = I18n.t('record_deleted') - redirect_to admin_api_user_path(@api_user) + redirect_to admin_registrar_api_user_path(@api_user.registrar, @api_user) else flash.now[:alert] = I18n.t('failed_to_delete_record') render 'show' diff --git a/app/controllers/admin/contacts_controller.rb b/app/controllers/admin/contacts_controller.rb index b53d366ab..793fa1209 100644 --- a/app/controllers/admin/contacts_controller.rb +++ b/app/controllers/admin/contacts_controller.rb @@ -3,6 +3,7 @@ module Admin load_and_authorize_resource before_action :set_contact, only: [:show] helper_method :ident_types + helper_method :domain_filter_params def index params[:q] ||= {} @@ -12,19 +13,27 @@ module Admin search_params[:registrant_domains_id_not_null] = 1 end - contacts = Contact.includes(:registrar).joins(:registrar).select('contacts.*, registrars.name') + contacts = Contact.includes(:registrar).joins(:registrar) + .select('contacts.*, registrars.name') contacts = contacts.filter_by_states(params[:statuses_contains].join(',')) if params[:statuses_contains] - contacts = contacts.where("ident_country_code is null or ident_country_code=''") if params[:only_no_country_code].eql?('1') - + contacts = filter_by_flags(contacts) normalize_search_parameters do @q = contacts.search(search_params) - @contacts = @q.result.uniq.page(params[:page]) + @contacts = @q.result.distinct.page(params[:page]) end @contacts = @contacts.per(params[:results_per_page]) if params[:results_per_page].to_i.positive? end + def filter_by_flags(contacts) + if params[:only_no_country_code].eql?('1') + contacts = contacts.where("ident_country_code is null or ident_country_code=''") + end + contacts = contacts.email_verification_failed if params[:email_verification_failed].eql?('1') + contacts + end + def search render json: Contact.search_by_query(params[:q]) end @@ -84,5 +93,9 @@ module Admin def ident_types Contact::Ident.types end + + def domain_filter_params + params.permit(:domain_filter) + end end end diff --git a/app/controllers/admin/disputes_controller.rb b/app/controllers/admin/disputes_controller.rb new file mode 100644 index 000000000..8a8997f63 --- /dev/null +++ b/app/controllers/admin/disputes_controller.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +module Admin + class DisputesController < BaseController + load_and_authorize_resource + before_action :set_dispute, only: %i[show edit update delete] + + # GET /admin/disputes + def index + params[:q] ||= {} + @disputes = sortable_dispute_query_for(Dispute.active.all, params[:q]) + @closed_disputes = sortable_dispute_query_for(Dispute.closed.all, params[:q], closed: true) + end + + # GET /admin/disputes/1 + def show; end + + # GET /admin/disputes/new + def new + @dispute = Dispute.new + end + + # GET /admin/disputes/1/edit + def edit; end + + # POST /admin/disputes + def create + @dispute = Dispute.new(dispute_params) + if @dispute.save + notice = 'Dispute was successfully created' + notice += @dispute.domain ? '.' : ' for domain that is not registered.' + + redirect_to admin_disputes_url, notice: notice + else + render :new + end + end + + # PATCH/PUT /admin/disputes/1 + def update + if @dispute.update(dispute_params.except(:domain_name)) + redirect_to admin_disputes_url, notice: 'Dispute was successfully updated.' + else + render :edit + end + end + + # DELETE /admin/disputes/1 + def delete + @dispute.close(initiator: 'Admin') + redirect_to admin_disputes_url, notice: 'Dispute was successfully closed.' + end + + private + + def sortable_dispute_query_for(disputes, query, closed: false) + @q = disputes.order(:domain_name).search(query) + disputes = @q.result.page(closed ? params[:closed_page] : params[:page]) + return disputes.per(params[:results_per_page]) if params[:results_per_page].present? + + disputes + end + + # Use callbacks to share common setup or constraints between actions. + def set_dispute + @dispute = Dispute.find(params[:id]) + end + + # Only allow a trusted parameter "white list" through. + def dispute_params + params.require(:dispute).permit(:domain_name, :password, :starts_at, :comment) + end + end +end diff --git a/app/controllers/admin/domains/force_delete_controller.rb b/app/controllers/admin/domains/force_delete_controller.rb index 946231077..c61f050d2 100644 --- a/app/controllers/admin/domains/force_delete_controller.rb +++ b/app/controllers/admin/domains/force_delete_controller.rb @@ -5,21 +5,27 @@ module Admin authorize! :manage, domain domain.transaction do - domain.schedule_force_delete + domain.schedule_force_delete(type: force_delete_type) domain.registrar.notifications.create!(text: t('force_delete_set_on_domain', - domain_name: domain.name)) + domain_name: domain.name, + outzone_date: domain.outzone_date, + purge_date: domain.purge_date)) - if notify_by_email? - DomainDeleteMailer.forced(domain: domain, - registrar: domain.registrar, - registrant: domain.registrant, - template_name: params[:template_name]).deliver_now - end + notify_by_email if notify_by_email? end redirect_to edit_admin_domain_url(domain), notice: t('.scheduled') end + def notify_by_email + if force_delete_type == :fast_track + send_email + domain.update(contact_notification_sent_date: Time.zone.today) + else + domain.update(template_name: params[:template_name]) + end + end + def destroy authorize! :manage, domain domain.cancel_force_delete @@ -33,7 +39,22 @@ module Admin end def notify_by_email? - ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:notify_by_email]) + ActiveRecord::Type::Boolean.new.cast(params[:notify_by_email]) + end + + def send_email + DomainDeleteMailer.forced(domain: domain, + registrar: domain.registrar, + registrant: domain.registrant, + template_name: params[:template_name]).deliver_now + end + + def force_delete_type + soft_delete? ? :soft : :fast_track + end + + def soft_delete? + ActiveRecord::Type::Boolean.new.cast(params[:soft_delete]) end end end diff --git a/app/controllers/admin/legal_documents_controller.rb b/app/controllers/admin/legal_documents_controller.rb index a07949875..68b95877d 100644 --- a/app/controllers/admin/legal_documents_controller.rb +++ b/app/controllers/admin/legal_documents_controller.rb @@ -5,7 +5,11 @@ module Admin def show @ld = LegalDocument.find(params[:id]) filename = @ld.path.split('/').last - send_data File.open(@ld.path).read, filename: filename + file = File.open(@ld.path)&.read + send_data file, filename: filename + rescue Errno::ENOENT + flash[:notice] = I18n.t('legal_doc_not_found') + redirect_to [:admin, @ld.documentable] end end end diff --git a/app/controllers/admin/pending_deletes_controller.rb b/app/controllers/admin/pending_deletes_controller.rb index 9cc8702c5..8e39b306b 100644 --- a/app/controllers/admin/pending_deletes_controller.rb +++ b/app/controllers/admin/pending_deletes_controller.rb @@ -29,7 +29,6 @@ module Admin # steal token token = @domain.registrant_verification_token @registrant_verification = RegistrantVerification.new(domain_id: @domain.id, - domain_name: @domain.name, verification_token: token) end diff --git a/app/controllers/admin/pending_updates_controller.rb b/app/controllers/admin/pending_updates_controller.rb index 4a2e5ec7c..72b1ace6e 100644 --- a/app/controllers/admin/pending_updates_controller.rb +++ b/app/controllers/admin/pending_updates_controller.rb @@ -26,7 +26,6 @@ module Admin # steal token token = @domain.registrant_verification_token @registrant_verification = RegistrantVerification.new(domain_id: @domain.id, - domain_name: @domain.name, verification_token: token) end diff --git a/app/controllers/admin/registrars_controller.rb b/app/controllers/admin/registrars_controller.rb index b925a8156..27116d871 100644 --- a/app/controllers/admin/registrars_controller.rb +++ b/app/controllers/admin/registrars_controller.rb @@ -74,6 +74,8 @@ module Admin :vat_rate, :accounting_customer_code, :billing_email, + :legaldoc_optout, + :legaldoc_optout_comment, :iban, :language) end diff --git a/app/controllers/admin/zonefiles_controller.rb b/app/controllers/admin/zonefiles_controller.rb index 30b4b9a61..4fd84bb77 100644 --- a/app/controllers/admin/zonefiles_controller.rb +++ b/app/controllers/admin/zonefiles_controller.rb @@ -13,7 +13,7 @@ module Admin send_data @zonefile, filename: "#{params[:origin]}.txt" else flash[:alert] = 'Origin not supported' - redirect_to :back + redirect_back(fallback_location: root_path) end end end diff --git a/app/controllers/api/cors_controller.rb b/app/controllers/api/cors_controller.rb index cd4c1a8d3..8dfebf026 100644 --- a/app/controllers/api/cors_controller.rb +++ b/app/controllers/api/cors_controller.rb @@ -5,7 +5,7 @@ module Api def cors_preflight_check set_access_control_headers - render text: '' + render plain: '' end def set_access_control_headers diff --git a/app/controllers/api/v1/auctions_controller.rb b/app/controllers/api/v1/auctions_controller.rb index bf92be930..de8e94442 100644 --- a/app/controllers/api/v1/auctions_controller.rb +++ b/app/controllers/api/v1/auctions_controller.rb @@ -30,6 +30,8 @@ module Api raise "Invalid status #{params[:status]}" end + auction.mark_deadline(params[:registration_deadline]) if params[:registration_deadline] + if auction.payment_not_received? || auction.domain_not_registered? update_whois_from_auction(Auction.pending(auction.domain)) else diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index c93160d9c..54930edf9 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -1,8 +1,8 @@ -require 'rails5_api_controller_backport' - module Api module V1 class BaseController < ActionController::API + rescue_from ActiveRecord::RecordNotFound, with: :not_found_error + private def authenticate @@ -10,6 +10,12 @@ module Api head :unauthorized unless ip_allowed end + def not_found_error + uuid = params['uuid'] + json = { error: 'Not Found', uuid: uuid, message: 'Record not found' } + render json: json, status: :not_found + end + def allowed_ips ENV['auction_api_allowed_ips'].split(',').map(&:strip) end diff --git a/app/controllers/api/v1/registrant/auth_controller.rb b/app/controllers/api/v1/registrant/auth_controller.rb index c1fe3fbf8..03dfa45f3 100644 --- a/app/controllers/api/v1/registrant/auth_controller.rb +++ b/app/controllers/api/v1/registrant/auth_controller.rb @@ -1,4 +1,3 @@ -require 'rails5_api_controller_backport' require 'auth_token/auth_token_creator' module Api @@ -16,7 +15,7 @@ module Api end def eid - user = RegistrantUser.find_or_create_by_api_data(eid_params) + user = RegistrantUser.find_or_create_by_api_data(eid_params.to_h) token = create_token(user) if token diff --git a/app/controllers/api/v1/registrant/base_controller.rb b/app/controllers/api/v1/registrant/base_controller.rb index 05702b4c9..16980be8b 100644 --- a/app/controllers/api/v1/registrant/base_controller.rb +++ b/app/controllers/api/v1/registrant/base_controller.rb @@ -1,4 +1,3 @@ -require 'rails5_api_controller_backport' require 'auth_token/auth_token_decryptor' module Api @@ -45,7 +44,7 @@ module Api # This controller does not inherit from ApplicationController, # so user_for_paper_trail method is not usable. def set_paper_trail_whodunnit - ::PaperTrail.whodunnit = current_registrant_user.id_role_username + ::PaperTrail.request.whodunnit = current_registrant_user.id_role_username end def show_not_found_error diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dec34acbf..5a6b45668 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,9 +1,10 @@ class ApplicationController < ActionController::Base check_authorization unless: :devise_controller? + before_action :set_paper_trail_whodunnit # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. - protect_from_forgery with: :exception + protect_from_forgery with: :exception, prepend: true before_action do resource = controller_name.singularize.to_sym @@ -32,4 +33,4 @@ class ApplicationController < ActionController::Base def available_languages { en: 'English', et: 'Estonian' }.invert end -end \ No newline at end of file +end diff --git a/app/controllers/epp/base_controller.rb b/app/controllers/epp/base_controller.rb index d49112643..e9d58a4ed 100644 --- a/app/controllers/epp/base_controller.rb +++ b/app/controllers/epp/base_controller.rb @@ -1,9 +1,8 @@ module Epp class BaseController < ActionController::Base class AuthorizationError < StandardError; end - - check_authorization skip_before_action :verify_authenticity_token + check_authorization layout false before_action :ensure_session_id_passed @@ -11,7 +10,7 @@ module Epp before_action :latin_only before_action :validate_against_schema before_action :validate_request - before_action :update_epp_session, if: 'signed_in?' + before_action :update_epp_session, if: -> { signed_in? } around_action :wrap_exceptions @@ -21,6 +20,7 @@ module Epp rescue_from StandardError, with: :respond_with_command_failed_error rescue_from AuthorizationError, with: :respond_with_authorization_error rescue_from ActiveRecord::RecordNotFound, with: :respond_with_object_does_not_exist_error + before_action :set_paper_trail_whodunnit protected @@ -119,7 +119,7 @@ module Epp end def render_epp_response(*args) - @response = render_to_string(*args, formats: 'xml') + @response = render_to_string(*args, formats: [:xml]) render xml: @response write_to_epp_log end @@ -395,7 +395,12 @@ module Epp end def log_exception(exception) + logger.error(([exception.message] + exception.backtrace).join($INPUT_RECORD_SEPARATOR)) notify_airbrake(exception) end + + def user_for_paper_trail + current_user ? current_user.id_role_username : 'anonymous' + end end end diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb index b6a26a626..df9755af6 100644 --- a/app/controllers/epp/contacts_controller.rb +++ b/app/controllers/epp/contacts_controller.rb @@ -1,3 +1,5 @@ +require 'deserializers/xml/contact_update' + module Epp class ContactsController < BaseController before_action :find_contact, only: [:info, :update, :delete] @@ -43,9 +45,14 @@ module Epp def update authorize! :update, @contact, @password - frame = params[:parsed_frame] + collected_data = ::Deserializers::Xml::ContactUpdate.new(params[:parsed_frame]) + action = Actions::ContactUpdate.new(@contact, + collected_data.contact, + collected_data.legal_document, + collected_data.ident, + current_user) - if @contact.update_attributes(frame, current_user) + if action.call if !address_processing? && address_given? @response_code = 1100 @response_description = t('epp.contacts.completed_without_address') diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 2b708d66c..d9a8b2b5d 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -2,6 +2,7 @@ module Epp class DomainsController < BaseController before_action :find_domain, only: %i[info renew update transfer delete] before_action :find_password, only: %i[info update transfer delete] + before_action :set_paper_trail_whodunnit def info authorize! :info, @domain @@ -91,7 +92,7 @@ module Epp status: Auction.statuses[:payment_received]) active_auction.domain_registered! end - + Dispute.close_by_domain(@domain.name) render_epp_response '/epp/domains/create' else handle_errors(@domain) @@ -102,21 +103,17 @@ module Epp def update authorize! :update, @domain, @password - if @domain.update(params[:parsed_frame], current_user) - if @domain.epp_pending_update.present? - render_epp_response '/epp/domains/success_pending' - else - render_epp_response '/epp/domains/success' - end - else - handle_errors(@domain) - end + updated = @domain.update(params[:parsed_frame], current_user) + (handle_errors(@domain) && return) unless updated + + pending = @domain.epp_pending_update.present? + render_epp_response "/epp/domains/success#{'_pending' if pending}" end def delete authorize! :delete, @domain, @password - handle_errors(@domain) and return unless @domain.can_be_deleted? + (handle_errors(@domain) && return) unless @domain.can_be_deleted? if @domain.epp_destroy(params[:parsed_frame], current_user.id) if @domain.epp_pending_delete.present? @@ -240,7 +237,7 @@ module Epp mutually_exclusive 'keyData', 'dsData' @prefix = nil - requires 'extension > extdata > legalDocument' + requires 'extension > extdata > legalDocument' if current_user.legaldoc_mandatory? optional_attribute 'period', 'unit', values: %w(d m y) @@ -249,7 +246,7 @@ module Epp def validate_update if element_count('update > chg > registrant') > 0 - requires 'extension > extdata > legalDocument' + requires 'extension > extdata > legalDocument' if current_user.legaldoc_mandatory? end @prefix = 'update > update >' @@ -259,8 +256,6 @@ module Epp end def validate_delete - requires 'extension > extdata > legalDocument' - @prefix = 'delete > delete >' requires 'name' end @@ -311,6 +306,7 @@ module Epp def status_editing_disabled return true if Setting.client_status_editing_enabled + return true if check_client_hold return true if params[:parsed_frame].css('status').empty? epp_errors << { code: '2306', @@ -318,6 +314,11 @@ module Epp } end + def check_client_hold + statuses = params[:parsed_frame].css('status').map { |element| element['s'] } + statuses == [::DomainStatus::CLIENT_HOLD] + end + def balance_ok?(operation, period = nil, unit = nil) @domain_pricelist = @domain.pricelist(operation, period.try(:to_i), unit) if @domain_pricelist.try(:price) # checking if price list is not found diff --git a/app/controllers/epp/sessions_controller.rb b/app/controllers/epp/sessions_controller.rb index f1cd35b33..b1c7fbbfb 100644 --- a/app/controllers/epp/sessions_controller.rb +++ b/app/controllers/epp/sessions_controller.rb @@ -1,6 +1,7 @@ module Epp class SessionsController < BaseController skip_authorization_check only: [:hello, :login, :logout] + before_action :set_paper_trail_whodunnit def hello render_epp_response('greeting') @@ -29,7 +30,8 @@ module Epp end if !Rails.env.development? && (!webclient_request && @api_user) - unless @api_user.api_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) + unless @api_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], + request.env['HTTP_SSL_CLIENT_S_DN_CN']) epp_errors << { msg: 'Authentication error; server closing connection (certificate is not valid)', code: '2501' diff --git a/app/controllers/registrant/contacts_controller.rb b/app/controllers/registrant/contacts_controller.rb index a4b335def..49070ebde 100644 --- a/app/controllers/registrant/contacts_controller.rb +++ b/app/controllers/registrant/contacts_controller.rb @@ -1,10 +1,12 @@ class Registrant::ContactsController < RegistrantController helper_method :domain helper_method :fax_enabled? + helper_method :domain_filter_params skip_authorization_check only: %i[edit update] + before_action :set_contact, only: [:show] def show - @contact = current_user_contacts.find(params[:id]) + @requester_contact = Contact.find_by(ident: current_registrant_user.ident) authorize! :read, @contact end @@ -29,6 +31,13 @@ class Registrant::ContactsController < RegistrantController private + def set_contact + id = params[:id] + contact = domain.contacts.find_by(id: id) || current_user_contacts.find_by(id: id) + contact ||= Contact.find_by(id: id, ident: domain.registrant.ident) + @contact = contact + end + def domain current_user_domains.find(params[:domain_id]) end @@ -99,4 +108,8 @@ class Registrant::ContactsController < RegistrantController http.request(request) end end + + def domain_filter_params + params.permit(:domain_filter) + end end diff --git a/app/controllers/registrant/domain_delete_confirms_controller.rb b/app/controllers/registrant/domain_delete_confirms_controller.rb index 59492fefb..337ca2403 100644 --- a/app/controllers/registrant/domain_delete_confirms_controller.rb +++ b/app/controllers/registrant/domain_delete_confirms_controller.rb @@ -4,6 +4,7 @@ class Registrant::DomainDeleteConfirmsController < RegistrantController def show return if params[:confirmed] || params[:rejected] + @domain = Domain.find(params[:id]) @domain = nil unless @domain.registrant_delete_confirmable?(params[:token]) end @@ -16,28 +17,28 @@ class Registrant::DomainDeleteConfirmsController < RegistrantController end @registrant_verification = RegistrantVerification.new(domain_id: @domain.id, - domain_name: @domain.name, verification_token: params[:token]) initiator = current_registrant_user ? current_registrant_user.username : t(:user_not_authenticated) - if params[:rejected] - if @registrant_verification.domain_registrant_delete_reject!("email link #{initiator}") - flash[:notice] = t(:registrant_domain_verification_rejected) - redirect_to registrant_domain_delete_confirm_path(@domain.id, rejected: true) - else - flash[:alert] = t(:registrant_domain_delete_rejected_failed) - return render 'show' - end - elsif params[:confirmed] - if @registrant_verification.domain_registrant_delete_confirm!("email link #{initiator}") - flash[:notice] = t(:registrant_domain_verification_confirmed) - redirect_to registrant_domain_delete_confirm_path(@domain.id, confirmed: true) - else - flash[:alert] = t(:registrant_domain_delete_confirmed_failed) - return render 'show' - end + confirmed = params[:confirmed] ? true : false + action = if confirmed + @registrant_verification.domain_registrant_delete_confirm!("email link #{initiator}") + else + @registrant_verification.domain_registrant_delete_reject!("email link #{initiator}") + end + + fail_msg = t("registrant_domain_delete_#{confirmed ? 'confirmed' : 'rejected'}_failed".to_sym) + success_msg = t("registrant_domain_verification_#{confirmed ? 'confirmed' : 'rejected'}".to_sym) + + flash[:alert] = action ? success_msg : fail_msg + (render 'show' && return) unless action + + if confirmed + redirect_to registrant_domain_delete_confirm_path(@domain.id, confirmed: true) + else + redirect_to registrant_domain_delete_confirm_path(@domain.id, rejected: true) end end end diff --git a/app/controllers/registrant/domain_update_confirms_controller.rb b/app/controllers/registrant/domain_update_confirms_controller.rb index d0bc1e7a1..0e4f2a582 100644 --- a/app/controllers/registrant/domain_update_confirms_controller.rb +++ b/app/controllers/registrant/domain_update_confirms_controller.rb @@ -16,7 +16,6 @@ class Registrant::DomainUpdateConfirmsController < RegistrantController end @registrant_verification = RegistrantVerification.new(domain_id: @domain.id, - domain_name: @domain.name, verification_token: params[:token]) initiator = current_registrant_user ? current_registrant_user.username : @@ -32,6 +31,8 @@ class Registrant::DomainUpdateConfirmsController < RegistrantController end elsif params[:confirmed] if @registrant_verification.domain_registrant_change_confirm!("email link, #{initiator}") + Dispute.close_by_domain(@domain.name) if @domain.disputed? + flash[:notice] = t(:registrant_domain_verification_confirmed) redirect_to registrant_domain_update_confirm_path(@domain.id, confirmed: true) else diff --git a/app/controllers/registrant/domains_controller.rb b/app/controllers/registrant/domains_controller.rb index fc66806e2..216f87e54 100644 --- a/app/controllers/registrant/domains_controller.rb +++ b/app/controllers/registrant/domains_controller.rb @@ -76,4 +76,4 @@ class Registrant::DomainsController < RegistrantController params.require(:q).permit(:name_matches, :registrant_ident_eq, :valid_to_gteq, :valid_to_lteq, :results_per_page) end -end \ No newline at end of file +end diff --git a/app/controllers/registrant_controller.rb b/app/controllers/registrant_controller.rb index 6589d6f89..1e97281e7 100644 --- a/app/controllers/registrant_controller.rb +++ b/app/controllers/registrant_controller.rb @@ -1,5 +1,6 @@ class RegistrantController < ApplicationController before_action :authenticate_registrant_user! + before_action :set_paper_trail_whodunnit layout 'registrant/application' include Registrant::ApplicationHelper @@ -33,4 +34,4 @@ class RegistrantController < ApplicationController flash.now[:notice] = t('registrant.company_register_unavailable') current_registrant_user.direct_domains end -end \ No newline at end of file +end diff --git a/app/controllers/registrar/base_controller.rb b/app/controllers/registrar/base_controller.rb index 499d44594..54bed977b 100644 --- a/app/controllers/registrar/base_controller.rb +++ b/app/controllers/registrar/base_controller.rb @@ -6,6 +6,7 @@ class Registrar before_action :check_ip_restriction helper_method :depp_controller? helper_method :head_title_sufix + before_action :set_paper_trail_whodunnit protected diff --git a/app/controllers/registrar/contacts_controller.rb b/app/controllers/registrar/contacts_controller.rb index 49569d7a0..18af3a29f 100644 --- a/app/controllers/registrar/contacts_controller.rb +++ b/app/controllers/registrar/contacts_controller.rb @@ -3,6 +3,7 @@ class Registrar before_action :init_epp_contact helper_method :address_processing? helper_method :ident_types + helper_method :domain_filter_params def index authorize! :view, Depp::Contact @@ -16,12 +17,13 @@ class Registrar search_params[:registrant_domains_id_not_null] = 1 end - if params[:statuses_contains] - contacts = current_registrar_user.registrar.contacts.includes(:registrar).where( - "contacts.statuses @> ?::varchar[]", "{#{params[:statuses_contains].join(',')}}" - ) - else - contacts = current_registrar_user.registrar.contacts.includes(:registrar) + contacts = current_registrar_user.registrar.contacts.includes(:registrar) + status_list = params[:statuses_contains] + + if status_list + contacts_ids = contacts.select { |c| (c.statuses & status_list.to_a) == status_list.to_a } + .map(&:id) + contacts = contacts.where(id: contacts_ids) end normalize_search_parameters do @@ -68,7 +70,7 @@ class Registrar def create authorize! :create, Depp::Contact - @contact = Depp::Contact.new(params[:depp_contact]) + @contact = Depp::Contact.new(contact_params) if @contact.save redirect_to registrar_contact_url(@contact.id) @@ -79,9 +81,9 @@ class Registrar def update authorize! :edit, Depp::Contact - @contact = Depp::Contact.new(params[:depp_contact]) + @contact = Depp::Contact.new(contact_params) - if @contact.update_attributes(params[:depp_contact]) + if @contact.update_attributes(contact_params) redirect_to registrar_contact_url(@contact.id) else render 'edit' @@ -95,7 +97,7 @@ class Registrar def destroy authorize! :delete, Depp::Contact - @contact = Depp::Contact.new(params[:depp_contact]) + @contact = Depp::Contact.new(contact_params_for_delete) if @contact.delete redirect_to registrar_contacts_url, notice: t(:destroyed) @@ -104,6 +106,12 @@ class Registrar end end + protected + + def domain_filter_params + params.permit(:domain_filter) + end + private def init_epp_contact @@ -131,5 +139,22 @@ class Registrar def ident_types Contact::Ident.types end + + def contact_params + params.require(:depp_contact).permit(:id, + :name, + :email, + :phone, + :org_name, + :ident, :ident_type, :ident_country_code, + :street, :city, :zip, :state, :country_code, + :password, + :legal_document, + :code) + end + + def contact_params_for_delete + params.require(:depp_contact).permit(:id, :password, :legal_document) + end end end diff --git a/app/controllers/registrar/current_user_controller.rb b/app/controllers/registrar/current_user_controller.rb index 624ee294e..3a214322c 100644 --- a/app/controllers/registrar/current_user_controller.rb +++ b/app/controllers/registrar/current_user_controller.rb @@ -6,7 +6,7 @@ class Registrar raise 'Cannot switch to unlinked user' unless current_registrar_user.linked_with?(new_user) sign_in(:registrar_user, new_user) - redirect_to :back, notice: t('.switched', new_user: new_user) + redirect_back(fallback_location: root_path, notice: t('.switched', new_user: new_user)) end private diff --git a/app/controllers/registrar/domains_controller.rb b/app/controllers/registrar/domains_controller.rb index bdab2eefc..50ad0bd10 100644 --- a/app/controllers/registrar/domains_controller.rb +++ b/app/controllers/registrar/domains_controller.rb @@ -2,16 +2,17 @@ class Registrar class DomainsController < DeppController before_action :init_domain, except: :new helper_method :contacts + helper_method :search_params def index authorize! :view, Depp::Domain - params[:q] ||= {} - params[:q].delete_if { |_k, v| v.blank? } - if params[:q].length == 1 && params[:q][:name_matches].present? - @domain = Domain.find_by(name: params[:q][:name_matches]) - if @domain - redirect_to info_registrar_domains_url(domain_name: @domain.name) and return + if search_params.to_h.delete_if { |_key, value| value.blank? }.length == 1 && + search_params[:name_matches].present? + domain = Domain.find_by(name: search_params[:name_matches]) + + if domain + redirect_to info_registrar_domains_url(domain_name: domain.name) and return end end @@ -24,15 +25,15 @@ class Registrar end normalize_search_parameters do - @q = domains.search(params[:q]) + @q = domains.search(search_params) @domains = @q.result.page(params[:page]) - if @domains.count == 0 && params[:q][:name_matches] !~ /^%.+%$/ - # if we do not get any results, add wildcards to the name field and search again - n_cache = params[:q][:name_matches] - params[:q][:name_matches] = "%#{params[:q][:name_matches]}%" - @q = domains.search(params[:q]) + + # if we do not get any results, add wildcards to the name field and search again + if @domains.count == 0 && search_params[:name_matches] !~ /^%.+%$/ + new_search_params = search_params.to_h + new_search_params[:name_matches] = "%#{new_search_params[:name_matches]}%" + @q = domains.search(new_search_params) @domains = @q.result.page(params[:page]) - params[:q][:name_matches] = n_cache # we don't want to show wildcards in search form end end @@ -58,6 +59,7 @@ class Registrar def info authorize! :info, Depp::Domain @data = @domain.info(params[:domain_name]) if params[:domain_name] + @client_holded = client_holded(@data) if response_ok? render 'info' else @@ -84,7 +86,7 @@ class Registrar def create authorize! :create, Depp::Domain - @domain_params = params[:domain] + @domain_params = domain_params.to_h @data = @domain.create(@domain_params) if response_ok? @@ -98,12 +100,14 @@ class Registrar authorize! :update, Depp::Domain @data = @domain.info(params[:domain_name]) @domain_params = Depp::Domain.construct_params_from_server_data(@data) + @dispute = Dispute.active.find_by(domain_name: params[:domain_name]) end def update authorize! :update, Depp::Domain @domain_params = params[:domain] @data = @domain.update(@domain_params) + @dispute = Dispute.active.find_by(domain_name: @domain_params[:name]) if response_ok? redirect_to info_registrar_domains_url(domain_name: @domain_params[:name]) @@ -152,29 +156,60 @@ class Registrar render json: scope.pluck(:name, :code).map { |c| { display_key: "#{c.second} #{c.first}", value: c.second } } end + def remove_hold + authorize! :remove_hold, Depp::Domain + return unless params[:domain_name] + + @data = @domain.remove_hold(params) + + flash[:alert] = @data.css('msg').text unless response_ok? + redirect_to info_registrar_domains_url(domain_name: params[:domain_name]) + end + private def init_domain @domain = Depp::Domain.new(current_user: depp_current_user) end + def client_holded(data) + data.css('status')&.map { |element| element.attribute('s').value } + &.any? { |status| status == DomainStatus::CLIENT_HOLD } + end def contacts current_registrar_user.registrar.contacts end def normalize_search_parameters - ca_cache = params[:q][:valid_to_lteq] + ca_cache = search_params[:valid_to_lteq] begin - end_time = params[:q][:valid_to_lteq].try(:to_date) - params[:q][:valid_to_lteq] = end_time.try(:end_of_day) + end_time = search_params[:valid_to_lteq].try(:to_date) + search_params[:valid_to_lteq] = end_time.try(:end_of_day) rescue logger.warn('Invalid date') end yield - params[:q][:valid_to_lteq] = ca_cache + search_params[:valid_to_lteq] = ca_cache + end + + def search_params + params.fetch(:q, {}).permit(:name_matches, + :registrant_ident_eq, + :contacts_ident_eq, + :nameservers_hostname_eq, + :valid_to_gteq, + :valid_to_lteq, + :s) + end + + def domain_params + params.require(:domain).permit(:name, :period, :registrant, :registrant_helper, :reserved_pw, + :verified, :legal_document, contacts_attributes: {}, + nameservers_attributes: {}, + dnskeys_attributes: {}) end end end diff --git a/app/controllers/registrar/payments_controller.rb b/app/controllers/registrar/payments_controller.rb index 5be0d6562..598d13446 100644 --- a/app/controllers/registrar/payments_controller.rb +++ b/app/controllers/registrar/payments_controller.rb @@ -5,48 +5,51 @@ class Registrar skip_authorization_check # actually anyone can pay, no problems at all skip_before_action :authenticate_registrar_user!, :check_ip_restriction, only: [:back, :callback] - before_action :check_supported_payment_method + + before_action :check_supported_payment_method, only: [:pay] def pay invoice = Invoice.find(params[:invoice_id]) - bank = params[:bank] - opts = { - return_url: registrar_return_payment_with_url( - bank, invoice_id: invoice - ), - response_url: registrar_response_payment_with_url( - bank, invoice_id: invoice - ) - } - @payment = ::PaymentOrders.create_with_type(bank, invoice, opts) - @payment.create_transaction + channel = params[:bank] + + @payment_order = PaymentOrder.new_with_type(type: channel, invoice: invoice) + @payment_order.save + @payment_order.reload + + @payment_order.return_url = registrar_return_payment_with_url(@payment_order) + @payment_order.response_url = registrar_response_payment_with_url(@payment_order) + + @payment_order.save + @payment_order.reload end def back - invoice = Invoice.find(params[:invoice_id]) - opts = { response: params } - @payment = ::PaymentOrders.create_with_type(params[:bank], invoice, opts) - if @payment.valid_response_from_intermediary? && @payment.settled_payment? - @payment.complete_transaction + @payment_order = PaymentOrder.find_by!(id: params[:payment_order]) + @payment_order.update!(response: params.to_unsafe_h) - if invoice.paid? - flash[:notice] = t(:pending_applied) + if @payment_order.payment_received? + @payment_order.complete_transaction + + if @payment_order.invoice.paid? + flash[:notice] = t('.payment_successful') else - flash[:alert] = t(:something_wrong) + flash[:alert] = t('.successful_payment_backend_error') end else - flash[:alert] = t(:something_wrong) + @payment_order.create_failure_report + flash[:alert] = t('.payment_not_received') end - redirect_to registrar_invoice_path(invoice) + redirect_to registrar_invoice_path(@payment_order.invoice) end def callback - invoice = Invoice.find(params[:invoice_id]) - opts = { response: params } - @payment = ::PaymentOrders.create_with_type(params[:bank], invoice, opts) + @payment_order = PaymentOrder.find_by!(id: params[:payment_order]) + @payment_order.update!(response: params.to_unsafe_h) - if @payment.valid_response_from_intermediary? && @payment.settled_payment? - @payment.complete_transaction + if @payment_order.payment_received? + @payment_order.complete_transaction + else + @payment_order.create_failure_report end render status: 200, json: { status: 'ok' } @@ -55,13 +58,9 @@ class Registrar private def check_supported_payment_method - return if supported_payment_method? - raise StandardError.new("Not supported payment method") - end + return if PaymentOrder.supported_method?(params[:bank], shortname: true) - - def supported_payment_method? - PaymentOrders::PAYMENT_METHODS.include?(params[:bank]) + raise(StandardError, 'Not supported payment method') end end end diff --git a/app/controllers/registrar/sessions_controller.rb b/app/controllers/registrar/sessions_controller.rb index c97c3155d..5bebe5619 100644 --- a/app/controllers/registrar/sessions_controller.rb +++ b/app/controllers/registrar/sessions_controller.rb @@ -31,7 +31,8 @@ class Registrar end if @depp_user.pki - unless @api_user.registrar_pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], request.env['HTTP_SSL_CLIENT_S_DN_CN']) + unless @api_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'], + request.env['HTTP_SSL_CLIENT_S_DN_CN'], api: false) @depp_user.errors.add(:base, :invalid_cert) end end @@ -55,7 +56,7 @@ class Registrar ip_allowed = restricted_ip.can_access_registrar_area?(resource.registrar) unless ip_allowed - render text: t('registrar.authorization.ip_not_allowed', ip: request.ip) + render plain: t('registrar.authorization.ip_not_allowed', ip: request.ip) warden.logout(:registrar_user) return end @@ -171,7 +172,7 @@ class Registrar return if allowed - render text: t('registrar.authorization.ip_not_allowed', ip: request.ip) + render plain: t('registrar.authorization.ip_not_allowed', ip: request.ip) end def current_ability @@ -205,4 +206,4 @@ class Registrar redirect_to new_registrar_user_session_url, alert: @depp_user.errors.full_messages.first end end -end \ No newline at end of file +end diff --git a/app/controllers/registrar/xml_consoles_controller.rb b/app/controllers/registrar/xml_consoles_controller.rb index 083dec532..b07b9cbee 100644 --- a/app/controllers/registrar/xml_consoles_controller.rb +++ b/app/controllers/registrar/xml_consoles_controller.rb @@ -19,7 +19,7 @@ class Registrar xml_dir_path = Rails.root + 'app/views/registrar/xml_consoles/epp_requests' xml = File.read("#{xml_dir_path}/#{params[:obj]}/#{params[:epp_action]}.xml") xml.gsub!('ABC-12345', "#{cl_trid}") - render text: xml + render plain: xml end end end diff --git a/app/controllers/repp/v1/auctions_controller.rb b/app/controllers/repp/v1/auctions_controller.rb new file mode 100644 index 000000000..4a5265d13 --- /dev/null +++ b/app/controllers/repp/v1/auctions_controller.rb @@ -0,0 +1,23 @@ +module Repp + module V1 + class AuctionsController < ActionController::API + def index + auctions = Auction.started + + render json: { count: auctions.count, + auctions: auctions_to_json(auctions) } + end + + private + + def auctions_to_json(auctions) + auctions.map do |e| + { + domain_name: e.domain, + punycode_domain_name: SimpleIDN.to_ascii(e.domain), + } + end + end + end + end +end diff --git a/app/controllers/repp/v1/retained_domains_controller.rb b/app/controllers/repp/v1/retained_domains_controller.rb new file mode 100644 index 000000000..c1bb458e9 --- /dev/null +++ b/app/controllers/repp/v1/retained_domains_controller.rb @@ -0,0 +1,15 @@ +module Repp + module V1 + class RetainedDomainsController < ActionController::API + def index + domains = RetainedDomains.new(query_params) + + render json: { count: domains.count, domains: domains.to_jsonable } + end + + def query_params + params.permit(:type) + end + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index a4a8e4912..5c742afce 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -33,6 +33,18 @@ module ApplicationHelper end end + def current_commit_link + hash = `git rev-parse --short HEAD` + current_repo = `git remote get-url origin`.gsub('com:', 'com/') + .gsub('git@', 'https://') + .gsub('.git', '') + + link_to hash.to_s, "#{current_repo}/commit/#{hash}", + class: 'footer-version-link', + target: '_blank', + rel: 'noopener' + end + def creator_link(model) return 'not present' if model.blank? return 'unknown' if model.creator.blank? @@ -96,4 +108,14 @@ module ApplicationHelper def body_css_class [controller_path.split('/').map!(&:dasherize), action_name.dasherize, 'page'].join('-') end -end \ No newline at end of file + + def verified_email_span(verification) + content_tag(:span, verification.email, class: verified_email_class(verification)) + end + + def verified_email_class(verification) + return 'text-danger' if verification.failed? + return 'text-primary' if verification.not_verified? + return 'text-success' if verification.verified? + end +end diff --git a/app/jobs/directo_invoice_forward_job.rb b/app/jobs/directo_invoice_forward_job.rb new file mode 100644 index 000000000..6c3eb034c --- /dev/null +++ b/app/jobs/directo_invoice_forward_job.rb @@ -0,0 +1,125 @@ +class DirectoInvoiceForwardJob < Que::Job + def run(monthly: false, dry: false) + @dry = dry + (@month = Time.zone.now - 1.month) if monthly + api_url = ENV['directo_invoice_url'] + sales_agent = Setting.directo_sales_agent + payment_term = Setting.directo_receipt_payment_term + @prepayment_product_id = Setting.directo_receipt_product_name + + @client = DirectoApi::Client.new(api_url, sales_agent, payment_term) + monthly ? send_monthly_invoices : send_receipts + end + + def send_receipts + unsent_invoices = Invoice.where(in_directo: false).non_cancelled + + Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices") + unsent_invoices.each do |invoice| + unless valid_invoice_conditions?(invoice) + Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped" + next + end + @client.invoices.add_with_schema(invoice: invoice.as_directo_json, schema: 'prepayment') + end + + sync_with_directo + end + + def send_monthly_invoices + Registrar.where.not(test_registrar: true).find_each do |registrar| + fetch_monthly_summary(registrar: registrar) + end + + return unless @client.invoices.count.positive? + + sync_with_directo + end + + def fetch_monthly_summary(registrar:) + return unless registrar.cash_account + + summary = registrar.monthly_summary(month: @month) + @client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil? + end + + def assign_monthly_numbers + if directo_counter_exceedable?(@client.invoices.count) + raise 'Directo Counter is going to be out of period!' + end + + min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) + directo_number = [Setting.directo_monthly_number_last.presence.try(:to_i), + min_directo].compact.max || 0 + + @client.invoices.each do |inv| + directo_number += 1 + inv.number = directo_number + end + end + + def valid_invoice_conditions?(invoice) + if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || + invoice.account_activity.bank_transaction.sum.nil? || + invoice.account_activity.bank_transaction.sum != invoice.total + return false + + end + + true + end + + def sync_with_directo + assign_monthly_numbers if @month + Rails.logger.info("[Directo] - attempting to send following XML:\n #{@client.invoices.as_xml}") + return if @dry + + res = @client.invoices.deliver(ssl_verify: false) + process_directo_response(res.body, @client.invoices.as_xml) + rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, + EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError + Rails.logger.info('[Directo] Failed to communicate via API') + end + + def process_directo_response(xml, req) + Rails.logger.info "[Directo] - Responded with body: #{xml}" + Nokogiri::XML(xml).css('Result').each do |res| + if @month + mark_invoice_as_sent(res: res, req: req) + else + inv = Invoice.find_by(number: res.attributes['docid'].value.to_i) + mark_invoice_as_sent(invoice: inv, res: res, req: req) + end + end + end + + def mark_invoice_as_sent(invoice: nil, res:, req:) + directo_record = Directo.new(response: res.as_json.to_h, + request: req, invoice_number: res.attributes['docid'].value.to_i) + if invoice + directo_record.item = invoice + invoice.update(in_directo: true) + else + update_directo_number(num: directo_record.invoice_number) + end + + directo_record.save! + end + + def update_directo_number(num:) + return unless num.to_i > Setting.directo_monthly_number_last.to_i + + Setting.directo_monthly_number_last = num.to_i + end + + def directo_counter_exceedable?(invoice_count) + min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) + max_directo = Setting.directo_monthly_number_max.presence.try(:to_i) + last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i), + min_directo].compact.max || 0 + + return true if max_directo && max_directo < (last_directo + invoice_count) + + false + end +end diff --git a/app/jobs/dispute_status_update_job.rb b/app/jobs/dispute_status_update_job.rb new file mode 100644 index 000000000..547d56868 --- /dev/null +++ b/app/jobs/dispute_status_update_job.rb @@ -0,0 +1,63 @@ +class DisputeStatusUpdateJob < Que::Job + def run(logger: Logger.new(STDOUT)) + @logger = logger + + @backlog = { 'activated': 0, 'closed': 0, 'activate_fail': [], 'close_fail': [] } + .with_indifferent_access + + close_disputes + activate_disputes + + @logger.info "DisputeStatusUpdateJob - All done. Closed #{@backlog['closed']} and " \ + "activated #{@backlog['activated']} disputes." + + show_failed_disputes unless @backlog['activate_fail'].empty? && @backlog['close_fail'].empty? + end + + def close_disputes + disputes = Dispute.where(closed: nil).where('expires_at < ?', Time.zone.today).all + @logger.info "DisputeStatusUpdateJob - Found #{disputes.count} closable disputes" + disputes.each do |dispute| + process_dispute(dispute, closing: true) + end + end + + def activate_disputes + disputes = Dispute.where(closed: nil, starts_at: Time.zone.today).all + @logger.info "DisputeStatusUpdateJob - Found #{disputes.count} activatable disputes" + + disputes.each do |dispute| + process_dispute(dispute, closing: false) + end + end + + def process_dispute(dispute, closing: false) + intent = closing ? 'close' : 'activate' + success = closing ? dispute.close(initiator: 'Job') : dispute.generate_data + create_backlog_entry(dispute: dispute, intent: intent, successful: success) + end + + def create_backlog_entry(dispute:, intent:, successful:) + if successful + @backlog["#{intent}d"] += 1 + @logger.info "DisputeStatusUpdateJob - #{intent}d dispute " \ + " for '#{dispute.domain_name}'" + else + @backlog["#{intent}_fail"] << dispute.id + @logger.info 'DisputeStatusUpdateJob - Failed to' \ + "#{intent} dispute for '#{dispute.domain_name}'" + end + end + + def show_failed_disputes + if @backlog['close_fail'].any? + @logger.info('DisputeStatusUpdateJob - Failed to close disputes with Ids:' \ + "#{@backlog['close_fail']}") + end + + return unless @backlog['activate_fail'].any? + + @logger.info('DisputeStatusUpdateJob - Failed to activate disputes with Ids:' \ + "#{@backlog['activate_fail']}") + end +end diff --git a/app/jobs/domain_delete_confirm_job.rb b/app/jobs/domain_delete_confirm_job.rb index a067ce175..e94f2432c 100644 --- a/app/jobs/domain_delete_confirm_job.rb +++ b/app/jobs/domain_delete_confirm_job.rb @@ -1,6 +1,6 @@ class DomainDeleteConfirmJob < Que::Job def run(domain_id, action, initiator = nil) - ::PaperTrail.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}" + ::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) diff --git a/app/jobs/domain_delete_job.rb b/app/jobs/domain_delete_job.rb index b45f96713..43e0bb844 100644 --- a/app/jobs/domain_delete_job.rb +++ b/app/jobs/domain_delete_job.rb @@ -3,7 +3,7 @@ class DomainDeleteJob < Que::Job def run(domain_id) domain = Domain.find(domain_id) - ::PaperTrail.whodunnit = "job - #{self.class.name}" + ::PaperTrail.request.whodunnit = "job - #{self.class.name}" WhoisRecord.where(domain_id: domain.id).destroy_all domain.destroy diff --git a/app/jobs/domain_update_confirm_job.rb b/app/jobs/domain_update_confirm_job.rb index 376858c42..f3665f1e8 100644 --- a/app/jobs/domain_update_confirm_job.rb +++ b/app/jobs/domain_update_confirm_job.rb @@ -1,6 +1,6 @@ class DomainUpdateConfirmJob < Que::Job def run(domain_id, action, initiator = nil) - ::PaperTrail.whodunnit = "job - #{self.class.name} - #{action} by #{initiator}" + ::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) diff --git a/app/jobs/regenerate_subzone_whoises_job.rb b/app/jobs/regenerate_subzone_whoises_job.rb new file mode 100644 index 000000000..280fa4088 --- /dev/null +++ b/app/jobs/regenerate_subzone_whoises_job.rb @@ -0,0 +1,11 @@ +class RegenerateSubzoneWhoisesJob < Que::Job + def run + subzones = DNS::Zone.all + + subzones.each do |zone| + next unless zone.subzone? + + UpdateWhoisRecordJob.enqueue zone.origin, 'zone' + end + end +end diff --git a/app/jobs/send_e_invoice_job.rb b/app/jobs/send_e_invoice_job.rb new file mode 100644 index 000000000..e281db14d --- /dev/null +++ b/app/jobs/send_e_invoice_job.rb @@ -0,0 +1,43 @@ +class SendEInvoiceJob < Que::Job + def run(invoice_id) + invoice = run_condition(Invoice.find_by(id: invoice_id)) + + invoice.to_e_invoice.deliver + ActiveRecord::Base.transaction do + invoice.update(e_invoice_sent_at: Time.zone.now) + log_success(invoice) + destroy + end + rescue StandardError => e + log_error(invoice: invoice, error: e) + raise e + end + + private + + def run_condition(invoice) + destroy unless invoice + destroy if invoice.do_not_send_e_invoice? + invoice + end + + def log_success(invoice) + id = invoice.try(:id) || invoice + message = "E-Invoice for an invoice with ID # #{id} was sent successfully" + logger.info message + end + + def log_error(invoice:, error:) + id = invoice.try(:id) || invoice + message = <<~TEXT.squish + There was an error sending e-invoice for invoice with ID # #{id}. + The error message was the following: #{error} + This job will retry. + TEXT + logger.error message + end + + def logger + Rails.logger + end +end diff --git a/app/jobs/update_whois_record_job.rb b/app/jobs/update_whois_record_job.rb index bee0e032c..2973d5a6b 100644 --- a/app/jobs/update_whois_record_job.rb +++ b/app/jobs/update_whois_record_job.rb @@ -1,16 +1,12 @@ class UpdateWhoisRecordJob < Que::Job def run(names, type) - ::PaperTrail.whodunnit = "job - #{self.class.name} - #{type}" + ::PaperTrail.request.whodunnit = "job - #{self.class.name} - #{type}" - klass = case type - when 'reserved'then ReservedDomain - when 'blocked' then BlockedDomain - when 'domain' then Domain - end + klass = determine_class(type) Array(names).each do |name| - record = klass.find_by(name: name) + record = find_record(klass, name) if record send "update_#{type}", record else @@ -19,7 +15,19 @@ class UpdateWhoisRecordJob < Que::Job 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 @@ -33,6 +41,13 @@ class UpdateWhoisRecordJob < Que::Job 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 @@ -41,14 +56,32 @@ class UpdateWhoisRecordJob < Que::Job 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) - Domain.where(name: name).any? - Whois::Record.where(name: name).delete_all + 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 diff --git a/app/jobs/verify_emails_job.rb b/app/jobs/verify_emails_job.rb new file mode 100644 index 000000000..75f4b7d91 --- /dev/null +++ b/app/jobs/verify_emails_job.rb @@ -0,0 +1,45 @@ +class VerifyEmailsJob < Que::Job + def run(verification_id) + email_address_verification = run_condition(EmailAddressVerification.find(verification_id)) + + return if email_address_verification.recently_verified? + + ActiveRecord::Base.transaction do + email_address_verification.verify + log_success(email_address_verification) + destroy + end + rescue StandardError => e + log_error(verification: email_address_verification, error: e) + raise e + end + + private + + def run_condition(email_address_verification) + destroy unless email_address_verification + destroy if email_address_verification.recently_verified? + + email_address_verification + end + + def logger + @logger ||= Logger.new(Rails.root.join('log', 'email_verification.log')) + end + + def log_success(verification) + email = verification.try(:email) || verification + message = "Email address #{email} verification done" + logger.info message + end + + def log_error(verification:, error:) + email = verification.try(:email) || verification + message = <<~TEXT.squish + There was an error verifying email #{email}. + The error message was the following: #{error} + This job will retry. + TEXT + logger.error message + end +end diff --git a/app/mailers/domain_delete_mailer.rb b/app/mailers/domain_delete_mailer.rb index eaac1a5af..1f08204bf 100644 --- a/app/mailers/domain_delete_mailer.rb +++ b/app/mailers/domain_delete_mailer.rb @@ -39,10 +39,12 @@ class DomainDeleteMailer < ApplicationMailer @registrant = RegistrantPresenter.new(registrant: registrant, view: view_context) @redemption_grace_period = Setting.redemption_grace_period + @expire_warning_period = Setting.expire_warning_period + @delete_period_length = @redemption_grace_period + @expire_warning_period subject = default_i18n_subject(domain_name: domain.name) mail(from: forced_email_from, - to: domain.primary_contact_emails, + to: domain.force_delete_contact_emails, subject: subject, template_path: 'mailers/domain_delete_mailer/forced', template_name: template_name) diff --git a/app/models/ability.rb b/app/models/ability.rb index 9a0676ac8..0e18f433a 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -50,6 +50,7 @@ class Ability can(:check, Epp::Domain) can(:create, Epp::Domain) can(:renew, Epp::Domain) { |d| d.registrar_id == @user.registrar_id } + can(:remove_hold, Epp::Domain) { |d| d.registrar_id == @user.registrar_id } can(:update, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } can(:transfer, Epp::Domain) can(:delete, Epp::Domain) { |d, pw| d.registrar_id == @user.registrar_id || d.transfer_code == pw } @@ -99,6 +100,7 @@ class Ability can :manage, Invoice can :manage, WhiteIp can :manage, AccountActivity + can :manage, Dispute can :read, ApiLog::EppLog can :read, ApiLog::ReppLog can :update, :pending diff --git a/app/models/account.rb b/app/models/account.rb index b7c43eab3..420f43e48 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -1,4 +1,4 @@ -class Account < ActiveRecord::Base +class Account < ApplicationRecord include Versions belongs_to :registrar, required: true diff --git a/app/models/account_activity.rb b/app/models/account_activity.rb index c5857631e..d8e6be4d4 100644 --- a/app/models/account_activity.rb +++ b/app/models/account_activity.rb @@ -1,4 +1,4 @@ -class AccountActivity < ActiveRecord::Base +class AccountActivity < ApplicationRecord include Versions belongs_to :account, required: true belongs_to :bank_transaction diff --git a/app/models/action.rb b/app/models/action.rb index 1d4f30d86..273dee821 100644 --- a/app/models/action.rb +++ b/app/models/action.rb @@ -1,5 +1,5 @@ -class Action < ActiveRecord::Base - has_paper_trail class_name: 'ActionVersion' +class Action < ApplicationRecord + has_paper_trail versions: { class_name: 'ActionVersion' } belongs_to :user belongs_to :contact @@ -16,4 +16,4 @@ class Action < ActiveRecord::Base raise 'Action object is missing' unless contact "contact_#{operation}".to_sym end -end \ No newline at end of file +end diff --git a/app/models/actions/contact_update.rb b/app/models/actions/contact_update.rb new file mode 100644 index 000000000..f8b39ecb4 --- /dev/null +++ b/app/models/actions/contact_update.rb @@ -0,0 +1,105 @@ +module Actions + class ContactUpdate + attr_reader :contact + attr_reader :new_attributes + attr_reader :legal_document + attr_reader :ident + attr_reader :user + + def initialize(contact, new_attributes, legal_document, ident, user) + @contact = contact + @new_attributes = new_attributes + @legal_document = legal_document + @ident = ident + @user = user + end + + def call + maybe_remove_address + maybe_update_statuses + maybe_update_ident + maybe_attach_legal_doc + commit + end + + def maybe_remove_address + return if Contact.address_processing? + + new_attributes.delete(:city) + new_attributes.delete(:zip) + new_attributes.delete(:street) + new_attributes.delete(:state) + new_attributes.delete(:country_code) + end + + def maybe_update_statuses + return unless Setting.client_status_editing_enabled + + new_statuses = + contact.statuses - new_attributes[:statuses_to_remove] + new_attributes[:statuses_to_add] + + new_attributes[:statuses] = new_statuses + end + + def maybe_attach_legal_doc + return unless legal_document + + document = contact.legal_documents.create( + document_type: legal_document[:type], + body: legal_document[:body] + ) + + contact.legal_document_id = document.id + end + + def maybe_update_ident + return unless ident[:ident] + + if contact.identifier.valid? + submitted_ident = ::Contact::Ident.new(code: ident[:ident], + type: ident[:ident_type], + country_code: ident[:ident_country_code]) + + if submitted_ident != contact.identifier + contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident')) + @error = true + end + else + ident_update_attempt = ident[:ident] != contact.ident + + if ident_update_attempt + contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.ident_update')) + @error = true + end + + identifier = ::Contact::Ident.new(code: ident[:ident], + type: ident[:ident_type], + country_code: ident[:ident_country_code]) + + identifier.validate + + contact.identifier = identifier + contact.ident_updated_at ||= Time.zone.now + end + end + + def commit + return false if @error + + contact.upid = user.registrar&.id + contact.up_date = Time.zone.now + + contact.attributes = new_attributes + + email_changed = contact.will_save_change_to_email? + old_email = contact.email_was + updated = contact.save + + if updated && email_changed && contact.registrant? + ContactMailer.email_changed(contact: contact, old_email: old_email).deliver_now + end + + updated + end + end +end diff --git a/app/models/admin_user.rb b/app/models/admin_user.rb index 07686e921..159578ab0 100644 --- a/app/models/admin_user.rb +++ b/app/models/admin_user.rb @@ -4,7 +4,7 @@ class AdminUser < User validates :identity_code, presence: true, if: -> { country_code == 'EE' } validates :email, presence: true validates :password, :password_confirmation, presence: true, if: :new_record? - validates :password_confirmation, presence: true, if: :encrypted_password_changed? + validates :password_confirmation, presence: true, if: :will_save_change_to_encrypted_password? validate :validate_identity_code, if: -> { country_code == 'EE' } ROLES = %w(user customer_service admin) # should not match to api_users roles diff --git a/app/models/api_log/db.rb b/app/models/api_log/db.rb index 255caffda..ca1162e8f 100644 --- a/app/models/api_log/db.rb +++ b/app/models/api_log/db.rb @@ -1,5 +1,5 @@ module ApiLog - class Db < ActiveRecord::Base + class Db < ApplicationRecord self.abstract_class = true # to_sym is needed because passing a string to ActiveRecord::Base.establish_connection # for a configuration lookup is deprecated diff --git a/app/models/api_user.rb b/app/models/api_user.rb index d08f17380..d7b264495 100644 --- a/app/models/api_user.rb +++ b/app/models/api_user.rb @@ -26,9 +26,9 @@ class ApiUser < User validates :username, uniqueness: true delegate :code, :name, to: :registrar, prefix: true + delegate :legaldoc_mandatory?, to: :registrar alias_attribute :login, :username - attr_accessor :registrar_typeahead SUPER = 'super' EPP = 'epp' @@ -44,7 +44,7 @@ class ApiUser < User after_initialize :set_defaults def set_defaults return unless new_record? - self.active = true unless active_changed? + self.active = true unless saved_change_to_active? end class << self @@ -53,10 +53,6 @@ class ApiUser < User end end - def registrar_typeahead - @registrar_typeahead || registrar || nil - end - def to_s username end @@ -69,24 +65,14 @@ class ApiUser < User registrar.notifications.unread end - def registrar_pki_ok?(crt, cn) - return false if crt.blank? || cn.blank? - crt = crt.split(' ').join("\n") - crt.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n") - crt.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----") - cert = OpenSSL::X509::Certificate.new(crt) - md5 = OpenSSL::Digest::MD5.new(cert.to_der).to_s - certificates.registrar.exists?(md5: md5, common_name: cn) - end + def pki_ok?(crt, com, api: true) + return false if crt.blank? || com.blank? - def api_pki_ok?(crt, cn) - return false if crt.blank? || cn.blank? - crt = crt.split(' ').join("\n") - crt.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n") - crt.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----") - cert = OpenSSL::X509::Certificate.new(crt) + origin = api ? certificates.api : certificates.registrar + cert = machine_readable_certificate(crt) md5 = OpenSSL::Digest::MD5.new(cert.to_der).to_s - certificates.api.exists?(md5: md5, common_name: cn) + + origin.exists?(md5: md5, common_name: com, revoked: false) end def linked_users @@ -98,4 +84,14 @@ class ApiUser < User def linked_with?(another_api_user) another_api_user.identity_code == self.identity_code end + + private + + def machine_readable_certificate(cert) + cert = cert.split(' ').join("\n") + cert.gsub!("-----BEGIN\nCERTIFICATE-----\n", "-----BEGIN CERTIFICATE-----\n") + cert.gsub!("\n-----END\nCERTIFICATE-----", "\n-----END CERTIFICATE-----") + + OpenSSL::X509::Certificate.new(cert) + end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 000000000..10a4cba84 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/auction.rb b/app/models/auction.rb index 80df11eef..791184d60 100644 --- a/app/models/auction.rb +++ b/app/models/auction.rb @@ -1,4 +1,4 @@ -class Auction < ActiveRecord::Base +class Auction < ApplicationRecord enum status: { started: 'started', awaiting_payment: 'awaiting_payment', @@ -23,10 +23,19 @@ class Auction < ActiveRecord::Base save! end + def whois_deadline + registration_deadline.try(:to_s, :iso8601) + end + def mark_as_no_bids no_bids! end + def mark_deadline(registration_deadline) + self.registration_deadline = registration_deadline + save! + end + def mark_as_payment_received self.status = self.class.statuses[:payment_received] generate_registration_code @@ -69,4 +78,4 @@ class Auction < ActiveRecord::Base def registration_code_matches?(code) registration_code == code end -end \ No newline at end of file +end diff --git a/app/models/bank_statement.rb b/app/models/bank_statement.rb index 5997927cf..c73e6bb44 100644 --- a/app/models/bank_statement.rb +++ b/app/models/bank_statement.rb @@ -1,4 +1,4 @@ -class BankStatement < ActiveRecord::Base +class BankStatement < ApplicationRecord include Versions has_many :bank_transactions @@ -25,10 +25,16 @@ class BankStatement < ActiveRecord::Base bank_transactions.build(bt_params) end + prepare_dir self.import_file_path = "#{ENV['bank_statement_import_dir']}/#{Time.zone.now.to_formatted_s(:number)}.txt" File.open(import_file_path, 'w') { |f| f.write(th6_file.open.read) } end + def prepare_dir + dirname = ENV['bank_statement_import_dir'] + FileUtils.mkdir_p(dirname) unless File.directory?(dirname) + end + def parse_th6_row(row) return parse_th6_header(row) if row[4, 3].strip == '000' return if row[4, 3].strip == '999' # skip footer @@ -45,7 +51,7 @@ class BankStatement < ActiveRecord::Base buyer_name: row[83, 35].strip, document_no: row[118, 8].strip, description: row[126, 140].strip, - sum: BigDecimal.new(row[268, 12].strip) / BigDecimal.new('100.0'), + sum: BigDecimal(row[268, 12].strip) / BigDecimal('100.0'), reference_no: row[280, 35].strip } end @@ -80,7 +86,9 @@ class BankStatement < ActiveRecord::Base status == FULLY_BINDED end - def bind_invoices - bank_transactions.unbinded.each(&:autobind_invoice) + def bind_invoices(manual: false) + bank_transactions.unbinded.each do |transaction| + transaction.autobind_invoice(manual: manual) + end end end diff --git a/app/models/bank_transaction.rb b/app/models/bank_transaction.rb index eb8c84622..f53a286ba 100644 --- a/app/models/bank_transaction.rb +++ b/app/models/bank_transaction.rb @@ -1,4 +1,4 @@ -class BankTransaction < ActiveRecord::Base +class BankTransaction < ApplicationRecord include Versions belongs_to :bank_statement has_one :account_activity @@ -13,53 +13,72 @@ class BankTransaction < ActiveRecord::Base def binded_invoice return unless binded? + account_activity.invoice end - - def invoice_num - return @invoice_no if defined?(@invoice_no) - - match = description.match(/^[^\d]*(\d+)/) - return unless match - - @invoice_no = match[1].try(:to_i) - end - def invoice - @invoice ||= registrar.invoices.find_by(number: invoice_num) if registrar + return unless registrar + + @invoice ||= registrar.invoices + .order(created_at: :asc) + .unpaid + .non_cancelled + .find_by(total: sum) end def registrar - @registrar ||= Invoice.find_by(reference_no: reference_no)&.buyer + @registrar ||= Invoice.find_by(reference_no: parsed_ref_number)&.buyer end - # For successful binding, reference number, invoice id and sum must match with the invoice - def autobind_invoice + def autobind_invoice(manual: false) return if binded? return unless registrar - return unless invoice_num return unless invoice return unless invoice.payable? - return if invoice.total != sum - create_activity(registrar, invoice) + channel = if manual + 'admin_payment' + else + 'system_payment' + end + create_internal_payment_record(channel: channel, invoice: invoice, + registrar: registrar) end - def bind_invoice(invoice_no) + def create_internal_payment_record(channel: nil, invoice:, registrar:) + if channel.nil? + create_activity(invoice.buyer, invoice) + return + end + + payment_order = PaymentOrder.new_with_type(type: channel, invoice: invoice) + payment_order.save! + + if create_activity(registrar, invoice) + payment_order.paid! + else + payment_order.update(notes: 'Failed to create activity', status: 'failed') + end + end + + def bind_invoice(invoice_no, manual: false) if binded? errors.add(:base, I18n.t('transaction_is_already_binded')) return end invoice = Invoice.find_by(number: invoice_no) + errors.add(:base, I18n.t('invoice_was_not_found')) unless invoice + validate_invoice_data(invoice) + return if errors.any? - unless invoice - errors.add(:base, I18n.t('invoice_was_not_found')) - return - end + create_internal_payment_record(channel: (manual ? 'admin_payment' : nil), invoice: invoice, + registrar: invoice.buyer) + end + def validate_invoice_data(invoice) if invoice.paid? errors.add(:base, I18n.t('invoice_is_already_binded')) return @@ -70,23 +89,21 @@ class BankTransaction < ActiveRecord::Base return end - if invoice.total != sum - errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match')) - return - end - - create_activity(invoice.buyer, invoice) + errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match')) if invoice.total != sum end def create_activity(registrar, invoice) - ActiveRecord::Base.transaction do - create_account_activity!(account: registrar.cash_account, - invoice: invoice, - sum: invoice.subtotal, - currency: currency, - description: description, - activity_type: AccountActivity::ADD_CREDIT) + activity = AccountActivity.new( + account: registrar.cash_account, bank_transaction: self, + invoice: invoice, sum: invoice.subtotal, + currency: currency, description: description, + activity_type: AccountActivity::ADD_CREDIT + ) + if activity.save reset_pending_registrar_balance_reload + true + else + false end end @@ -98,4 +115,12 @@ class BankTransaction < ActiveRecord::Base registrar.settings['balance_auto_reload'].delete('pending') registrar.save! end + + def parsed_ref_number + reference_no || ref_number_from_description + end + + def ref_number_from_description + /(\d{7})/.match(description)[0] + end end diff --git a/app/models/billing/price.rb b/app/models/billing/price.rb index b48c9f0bb..283a6e5bc 100644 --- a/app/models/billing/price.rb +++ b/app/models/billing/price.rb @@ -1,5 +1,5 @@ module Billing - class Price < ActiveRecord::Base + class Price < ApplicationRecord include Concerns::Billing::Price::Expirable belongs_to :zone, class_name: 'DNS::Zone', required: true diff --git a/app/models/blocked_domain.rb b/app/models/blocked_domain.rb index 26d5fedd7..d292827dc 100644 --- a/app/models/blocked_domain.rb +++ b/app/models/blocked_domain.rb @@ -1,4 +1,4 @@ -class BlockedDomain < ActiveRecord::Base +class BlockedDomain < ApplicationRecord include Versions before_save :generate_data after_destroy :remove_data diff --git a/app/models/certificate.rb b/app/models/certificate.rb index 212114862..d2428365a 100644 --- a/app/models/certificate.rb +++ b/app/models/certificate.rb @@ -1,6 +1,6 @@ require 'open3' -class Certificate < ActiveRecord::Base +class Certificate < ApplicationRecord include Versions belongs_to :api_user @@ -32,20 +32,21 @@ class Certificate < ActiveRecord::Base errors.add(:base, I18n.t(:invalid_csr_or_crt)) end - before_create :parse_metadata - def parse_metadata - if crt - pc = parsed_crt.try(:subject).try(:to_s) || '' - cn = pc.scan(/\/CN=(.+)/).flatten.first - self.common_name = cn.split('/').first - self.md5 = OpenSSL::Digest::MD5.new(parsed_crt.to_der).to_s - self.interface = API - elsif csr - pc = parsed_csr.try(:subject).try(:to_s) || '' - cn = pc.scan(/\/CN=(.+)/).flatten.first - self.common_name = cn.split('/').first - self.interface = REGISTRAR - end + validate :assign_metadata, on: :create + + def assign_metadata + origin = crt ? parsed_crt : parsed_csr + parse_metadata(origin) + rescue NoMethodError + errors.add(:base, I18n.t(:invalid_csr_or_crt)) + end + + def parse_metadata(origin) + pc = origin.subject.to_s + cn = pc.scan(%r{\/CN=(.+)}).flatten.first + self.common_name = cn.split('/').first + self.md5 = OpenSSL::Digest::MD5.new(origin.to_der).to_s if crt + self.interface = crt ? API : REGISTRAR end def parsed_crt @@ -116,6 +117,7 @@ class Certificate < ActiveRecord::Base -revoke #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") if err.match(/Data Base Updated/) || err.match(/ERROR:Already revoked/) + self.revoked = true save! @cached_status = REVOKED else diff --git a/app/models/concerns/contact/transferable.rb b/app/models/concerns/contact/transferable.rb index 3f151251a..987933a8d 100644 --- a/app/models/concerns/contact/transferable.rb +++ b/app/models/concerns/contact/transferable.rb @@ -3,7 +3,7 @@ module Concerns::Contact::Transferable included do validates :auth_info, presence: true - after_initialize :generate_auth_info, if: 'new_record? && auth_info.blank?' + after_initialize :generate_auth_info, if: -> { new_record? && auth_info.blank? } end def transfer(new_registrar) diff --git a/app/models/concerns/domain/disputable.rb b/app/models/concerns/domain/disputable.rb new file mode 100644 index 000000000..a05d7cea6 --- /dev/null +++ b/app/models/concerns/domain/disputable.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module Concerns + module Domain + module Disputable + extend ActiveSupport::Concern + + included do + validate :validate_disputed + end + + def mark_as_disputed + statuses.push(DomainStatus::DISPUTED) unless statuses.include?(DomainStatus::DISPUTED) + save + end + + def unmark_as_disputed + statuses.delete_if { |status| status == DomainStatus::DISPUTED } + save + end + + def in_disputed_list? + @in_disputed_list ||= Dispute.active.find_by(domain_name: name).present? + end + + def disputed? + Dispute.active.where(domain_name: name).any? + end + + def validate_disputed + return if persisted? || !in_disputed_list? + + if reserved_pw.blank? + errors.add(:base, :required_parameter_missing_disputed) + return false + end + + return if Dispute.valid_auth?(name, reserved_pw) + + errors.add(:base, :invalid_auth_information_reserved) + end + end + end +end diff --git a/app/models/concerns/domain/force_delete.rb b/app/models/concerns/domain/force_delete.rb index 5247ce93d..af3aaa7c7 100644 --- a/app/models/concerns/domain/force_delete.rb +++ b/app/models/concerns/domain/force_delete.rb @@ -1,32 +1,116 @@ -module Concerns::Domain::ForceDelete +module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength extend ActiveSupport::Concern + included do + store_accessor :force_delete_data, + :force_delete_type, + :contact_notification_sent_date, + :template_name + + scope :notification_not_sent, + lambda { + where("(force_delete_data->>'contact_notification_sent_date') is null") + } + end + + class_methods do + def force_delete_scheduled + where('force_delete_start <= ?', Time.zone.now) + end + end + def force_delete_scheduled? statuses.include?(DomainStatus::FORCE_DELETE) end - def schedule_force_delete + 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) if discarded? raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded' end + type == :fast_track ? force_delete_fast_track : force_delete_soft + end + + def add_force_delete_type(force_delete_type) + self.force_delete_type = force_delete_type + end + + def force_delete_fast_track preserve_current_statuses_for_force_delete add_force_delete_statuses - self.force_delete_date = Time.zone.today + Setting.redemption_grace_period.days + 1.day + add_force_delete_type(:fast) + self.force_delete_date = force_delete_fast_track_start_date + 1.day + self.force_delete_start = Time.zone.today + 1.day stop_all_pending_actions allow_deletion save(validate: false) end - def cancel_force_delete - restore_statuses_before_force_delete - remove_force_delete_statuses - self.force_delete_date = nil + def force_delete_soft + preserve_current_statuses_for_force_delete + add_force_delete_statuses + add_force_delete_type(:soft) + calculate_soft_delete_date + stop_all_pending_actions + allow_deletion save(validate: false) end + def clear_force_delete_data + self.force_delete_data = nil + end + + def cancel_force_delete + restore_statuses_before_force_delete + remove_force_delete_statuses + clear_force_delete_data + self.force_delete_date = nil + self.force_delete_start = nil + save(validate: false) + registrar.notifications.create!(text: I18n.t('force_delete_cancelled', domain_name: name)) + end + + def outzone_date + (force_delete_start || valid_to) + Setting.expire_warning_period.days + end + + def purge_date + (force_delete_date&.beginning_of_day || valid_to + Setting.expire_warning_period.days + + Setting.redemption_grace_period.days) + end + private + def calculate_soft_delete_date + years = (valid_to.to_date - Time.zone.today).to_i / 365 + soft_delete_dates(years) if years.positive? + end + + def soft_delete_dates(years) + self.force_delete_start = valid_to - years.years + 1.day + self.force_delete_date = force_delete_start + Setting.expire_warning_period.days + + Setting.redemption_grace_period.days + end + def stop_all_pending_actions statuses.delete(DomainStatus::PENDING_UPDATE) statuses.delete(DomainStatus::PENDING_TRANSFER) @@ -35,7 +119,7 @@ module Concerns::Domain::ForceDelete end def preserve_current_statuses_for_force_delete - self.statuses_before_force_delete = statuses + self.statuses_before_force_delete = statuses.clone end def restore_statuses_before_force_delete @@ -47,25 +131,21 @@ module Concerns::Domain::ForceDelete statuses << DomainStatus::FORCE_DELETE statuses << DomainStatus::SERVER_RENEW_PROHIBITED statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED - statuses << DomainStatus::SERVER_UPDATE_PROHIBITED - statuses << DomainStatus::PENDING_DELETE - - if (statuses & [DomainStatus::SERVER_HOLD, DomainStatus::CLIENT_HOLD]).empty? - statuses << DomainStatus::SERVER_MANUAL_INZONE - end end def remove_force_delete_statuses statuses.delete(DomainStatus::FORCE_DELETE) statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED) statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED) - statuses.delete(DomainStatus::SERVER_UPDATE_PROHIBITED) - statuses.delete(DomainStatus::PENDING_DELETE) - statuses.delete(DomainStatus::SERVER_MANUAL_INZONE) + statuses.delete(DomainStatus::CLIENT_HOLD) end def allow_deletion statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED) statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED) end + + def force_delete_fast_track_start_date + Time.zone.today + Setting.expire_warning_period.days + Setting.redemption_grace_period.days + end end diff --git a/app/models/concerns/domain/transferable.rb b/app/models/concerns/domain/transferable.rb index 56e77f34d..9de2fff83 100644 --- a/app/models/concerns/domain/transferable.rb +++ b/app/models/concerns/domain/transferable.rb @@ -57,7 +57,8 @@ module Concerns::Domain::Transferable def transfer_domain_contacts(new_registrar) copied_ids = [] - contacts.each do |contact| + domain_contacts.each do |dc| + contact = Contact.find(dc.contact_id) next if copied_ids.include?(contact.id) || contact.registrar == new_registrar if registrant_id_was == contact.id # registrant was copied previously, do not copy it again @@ -66,7 +67,11 @@ module Concerns::Domain::Transferable oc = contact.transfer(new_registrar) end - domain_contacts.where(contact_id: contact.id).update_all({ contact_id: oc.id }) # n+1 workaround + if domain_contacts.find_by(contact_id: oc.id, domain_id: id, type: dc.type).present? + dc.destroy + else + dc.update(contact_id: oc.id) + end copied_ids << contact.id end end diff --git a/app/models/concerns/email_verifable.rb b/app/models/concerns/email_verifable.rb new file mode 100644 index 000000000..dc512b2c8 --- /dev/null +++ b/app/models/concerns/email_verifable.rb @@ -0,0 +1,91 @@ +module Concerns + module EmailVerifable + extend ActiveSupport::Concern + + def email_verification + @email_verification ||= EmailAddressVerification.find_or_create_by(email: unicode_email, + domain: domain(email)) + end + + def billing_email_verification + return unless attribute_names.include?('billing_email') + + @billing_email_verification ||= EmailAddressVerification + .find_or_create_by(email: unicode_billing_email, + domain: domain(billing_email)) + end + + class_methods do + def domain(email) + Mail::Address.new(email).domain&.downcase || 'not_found' + rescue Mail::Field::IncompleteParseError + 'not_found' + end + + def local(email) + Mail::Address.new(email).local&.downcase || email + rescue Mail::Field::IncompleteParseError + email + end + + def punycode_to_unicode(email) + return email if domain(email) == 'not_found' + + local = local(email) + domain = SimpleIDN.to_unicode(domain(email)) + "#{local}@#{domain}"&.downcase + end + + def unicode_to_punycode(email) + return email if domain(email) == 'not_found' + + local = local(email) + domain = SimpleIDN.to_ascii(domain(email)) + "#{local}@#{domain}"&.downcase + end + end + + def unicode_billing_email + self.class.punycode_to_unicode(billing_email) + end + + def unicode_email + self.class.punycode_to_unicode(email) + end + + def domain(email) + SimpleIDN.to_unicode(self.class.domain(email)) + end + + def punycode_to_unicode(email) + self.class.punycode_to_unicode(email) + end + + def correct_email_format + return if email.blank? + + result = email_verification.verify + process_result(result: result, field: :email) + end + + def correct_billing_email_format + return if email.blank? + + result = billing_email_verification.verify + process_result(result: result, field: :billing_email) + end + + # rubocop:disable Metrics/LineLength + def process_result(result:, field:) + case result[:errors].keys.first + when :smtp + errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_smtp_check_error')) + when :mx + errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_mx_check_error')) + when :regex + errors.add(field, I18n.t('activerecord.errors.models.contact.attributes.email.email_regex_check_error')) + end + end + # rubocop:enable Metrics/LineLength + end +end diff --git a/app/models/concerns/epp_errors.rb b/app/models/concerns/epp_errors.rb index 7395732ca..c1e4fa2e1 100644 --- a/app/models/concerns/epp_errors.rb +++ b/app/models/concerns/epp_errors.rb @@ -20,7 +20,7 @@ module EppErrors epp_errors << collect_parent_errors(attr, errors) end - errors[:epp_errors] = epp_errors + errors.add(:epp_errors, epp_errors) errors[:epp_errors].flatten! end diff --git a/app/models/concerns/invoice/book_keeping.rb b/app/models/concerns/invoice/book_keeping.rb new file mode 100644 index 000000000..82e6506c9 --- /dev/null +++ b/app/models/concerns/invoice/book_keeping.rb @@ -0,0 +1,34 @@ +module Concerns + module Invoice + module BookKeeping + extend ActiveSupport::Concern + + def as_directo_json + invoice = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(self)) + invoice['customer'] = compose_directo_customer + invoice['issue_date'] = issue_date.strftime('%Y-%m-%d') + invoice['transaction_date'] = account_activity + .bank_transaction&.paid_at&.strftime('%Y-%m-%d') + invoice['language'] = buyer.language == 'en' ? 'ENG' : '' + invoice['invoice_lines'] = compose_directo_product + + invoice + end + + def compose_directo_product + [{ 'product_id': Setting.directo_receipt_product_name, 'description': order, + 'quantity': 1, 'price': ActionController::Base.helpers.number_with_precision( + subtotal, precision: 2, separator: '.' + ) }].as_json + end + + def compose_directo_customer + { + 'code': buyer.accounting_customer_code, + 'destination': buyer_country_code, + 'vat_reg_no': buyer_vat_no, + }.as_json + end + end + end +end diff --git a/app/models/concerns/job/force_delete.rb b/app/models/concerns/job/force_delete.rb new file mode 100644 index 000000000..316612d1e --- /dev/null +++ b/app/models/concerns/job/force_delete.rb @@ -0,0 +1,34 @@ +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 new file mode 100644 index 000000000..8f6ee227c --- /dev/null +++ b/app/models/concerns/job/force_delete_logging.rb @@ -0,0 +1,34 @@ +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 new file mode 100644 index 000000000..658c7a315 --- /dev/null +++ b/app/models/concerns/job/force_delete_notify.rb @@ -0,0 +1,31 @@ +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) + 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/concerns/registrar/book_keeping.rb b/app/models/concerns/registrar/book_keeping.rb new file mode 100644 index 000000000..60b9c2b1a --- /dev/null +++ b/app/models/concerns/registrar/book_keeping.rb @@ -0,0 +1,128 @@ +module Concerns + module Registrar + module BookKeeping + extend ActiveSupport::Concern + + DOMAIN_TO_PRODUCT = { 'ee': '01EE', 'com.ee': '02COM', 'pri.ee': '03PRI', + 'fie.ee': '04FIE', 'med.ee': '05MED' }.freeze + + def monthly_summary(month:) + activities = monthly_activites(month) + return unless activities.any? + + invoice = { + 'number': 1, + 'customer': compose_directo_customer, + 'language': language == 'en' ? 'ENG' : '', 'currency': activities.first.currency, + 'date': month.end_of_month.strftime('%Y-%m-%d') + }.as_json + + invoice['invoice_lines'] = prepare_invoice_lines(month: month, activities: activities) + + invoice + end + + def prepare_invoice_lines(month:, activities:) + lines = [] + + lines << { 'description': title_for_summary(month) } + activities.each do |activity| + fetch_invoice_lines(activity, lines) + end + lines << prepayment_for_all(lines) + + lines.as_json + end + + def title_for_summary(date) + I18n.with_locale(language == 'en' ? 'en' : 'et') do + I18n.t('registrar.monthly_summary_title', date: I18n.l(date, format: '%B %Y')) + end + end + + def fetch_invoice_lines(activity, lines) + price = load_price(activity) + if price.duration.include? 'year' + price.duration.to_i.times do |duration| + lines << new_monthly_invoice_line(activity: activity, duration: duration + 1).as_json + end + else + lines << new_monthly_invoice_line(activity: activity).as_json + end + end + + def monthly_activites(month) + AccountActivity.where(account_id: account_ids) + .where(created_at: month.beginning_of_month..month.end_of_month) + .where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]) + end + + def new_monthly_invoice_line(activity:, duration: nil) + price = load_price(activity) + line = { + 'product_id': DOMAIN_TO_PRODUCT[price.zone_name.to_sym], + 'quantity': 1, + 'unit': language == 'en' ? 'pc' : 'tk', + } + + finalize_invoice_line(line, price: price, duration: duration, activity: activity) + end + + def finalize_invoice_line(line, price:, activity:, duration:) + yearly = price.duration.include?('year') + + line['price'] = yearly ? (price.price.amount / price.duration.to_i) : price.price.amount + line['description'] = description_in_language(price: price, yearly: yearly) + + if duration.present? + add_product_timeframe(line: line, activity: activity, duration: duration) if duration > 1 + end + + line + end + + def add_product_timeframe(line:, activity:, duration:) + create_time = activity.created_at + line['start_date'] = (create_time + (duration - 1).year).end_of_month.strftime('%Y-%m-%d') + line['end_date'] = (create_time + (duration - 1).year + 1).end_of_month.strftime('%Y-%m-%d') + end + + def description_in_language(price:, yearly:) + timeframe_string = yearly ? 'yearly' : 'monthly' + locale_string = "registrar.invoice_#{timeframe_string}_product_description" + + I18n.with_locale(language == 'en' ? 'en' : 'et') do + I18n.t(locale_string, tld: ".#{price.zone_name}", length: price.duration.to_i) + end + end + + def prepayment_for_all(lines) + total = 0 + en = language == 'en' + lines.each { |l| total += l['quantity'].to_f * l['price'].to_f } + { + 'product_id': Setting.directo_receipt_product_name, + 'description': en ? 'Domains prepayment' : 'Domeenide ettemaks', + 'quantity': -1, + 'price': total, + 'unit': en ? 'pc' : 'tk', + } + end + + def compose_directo_customer + { + 'code': accounting_customer_code, + 'destination': address_country_code, + 'vat_reg_no': vat_no, + }.as_json + end + + def load_price(account_activity) + @pricelists ||= {} + return @pricelists[account_activity.price_id] if @pricelists.key? account_activity.price_id + + @pricelists[account_activity.price_id] = account_activity.price + end + end + end +end diff --git a/app/models/concerns/registrar/legal_doc.rb b/app/models/concerns/registrar/legal_doc.rb new file mode 100644 index 000000000..e2ed9f83e --- /dev/null +++ b/app/models/concerns/registrar/legal_doc.rb @@ -0,0 +1,16 @@ +module Concerns + module Registrar + module LegalDoc + extend ActiveSupport::Concern + + def legaldoc_mandatory? + !legaldoc_not_mandatory? + end + + def legaldoc_not_mandatory? + setting = Setting.find_by(var: 'legal_document_is_mandatory')&.value + legaldoc_optout || !setting + end + end + end +end diff --git a/app/models/concerns/remove_hold.rb b/app/models/concerns/remove_hold.rb new file mode 100644 index 000000000..1da3b5a7f --- /dev/null +++ b/app/models/concerns/remove_hold.rb @@ -0,0 +1,9 @@ +module RemoveHold + extend ActiveSupport::Concern + + def remove_hold(params) + xml = epp_xml.update(name: { value: params[:domain_name] }, + rem: [status: { attrs: { s: 'clientHold' }, value: '' }]) + current_user.request(xml) + end +end diff --git a/app/models/concerns/versions.rb b/app/models/concerns/versions.rb index 77bc484ae..033ebe52a 100644 --- a/app/models/concerns/versions.rb +++ b/app/models/concerns/versions.rb @@ -1,10 +1,17 @@ # Papertrail concerns is mainly tested at country spec module Versions extend ActiveSupport::Concern + WITH_CHILDREN = %w[Domain Contact].freeze included do attr_accessor :version_loader - has_paper_trail class_name: "#{model_name}Version" + + if WITH_CHILDREN.include?(model_name.name) + has_paper_trail versions: { class_name: "#{model_name}Version" }, + meta: { children: :children_log } + else + has_paper_trail versions: { class_name: "#{model_name}Version" } + end # add creator and updator before_create :add_creator @@ -12,23 +19,25 @@ module Versions before_update :add_updator def add_creator - self.creator_str = ::PaperTrail.whodunnit + self.creator_str = ::PaperTrail.request.whodunnit true end def add_updator - self.updator_str = ::PaperTrail.whodunnit + self.updator_str = ::PaperTrail.request.whodunnit true end def creator return nil if creator_str.blank? + creator = user_from_id_role_username creator_str creator.present? ? creator : creator_str end def updator return nil if updator_str.blank? + updator = user_from_id_role_username updator_str updator.present? ? updator : updator_str end @@ -45,25 +54,27 @@ module Versions # callbacks def touch_domain_version - domain.try(:touch_with_version) + domain.try(:touch) end def touch_domains_version - domains.each(&:touch_with_version) + domains.each(&:touch) end end module ClassMethods def all_versions_for(ids, time) - ver_klass = paper_trail_version_class + ver_klass = paper_trail.version_class from_history = ver_klass.where(item_id: ids.to_a). order(:item_id). preceding(time + 1, true). select("distinct on (item_id) #{ver_klass.table_name}.*"). map do |ver| - o = new(ver.object) + valid_columns = ver.item_type.constantize&.column_names + o = new(ver.object&.slice(*valid_columns)) o.version_loader = ver - ver.object_changes.to_h.each { |k, v| o.public_send("#{k}=", v[-1]) } + changes = ver.object_changes.to_h&.slice(*valid_columns) + changes.each { |k, v| o.public_send("#{k}=", v[-1]) } o end not_in_history = where(id: (ids.to_a - from_history.map(&:id))) diff --git a/app/models/concerns/whois_status_populate.rb b/app/models/concerns/whois_status_populate.rb new file mode 100644 index 000000000..616cc7d22 --- /dev/null +++ b/app/models/concerns/whois_status_populate.rb @@ -0,0 +1,15 @@ +module WhoisStatusPopulate + extend ActiveSupport::Concern + + def generate_json(record, domain_status:) + h = HashWithIndifferentAccess.new(name: record.name, status: [domain_status]) + return h if record.json.blank? + + status_arr = (record.json['status'] ||= []) + return record.json if status_arr.include? domain_status + + status_arr.push(domain_status) + record.json['status'] = status_arr + record.json + end +end diff --git a/app/models/concerns/zone/whois_queryable.rb b/app/models/concerns/zone/whois_queryable.rb new file mode 100644 index 000000000..2c453dbef --- /dev/null +++ b/app/models/concerns/zone/whois_queryable.rb @@ -0,0 +1,72 @@ +module Concerns + module Zone + module WhoisQueryable + extend ActiveSupport::Concern + + included do + after_save :update_whois_record, if: :subzone? + after_destroy :update_whois_record + end + + def subzone? + origin.include? '.' + end + + def update_whois_record + UpdateWhoisRecordJob.enqueue origin, 'zone' + end + + def generate_data + wr = Whois::Record.find_or_initialize_by(name: origin) + wr.json = generate_json + wr.save + end + + def generate_json + data = {}.with_indifferent_access + [domain_vars, registrar_vars, registrant_vars].each do |h| + data.merge!(h) + end + + data + end + + def domain_vars + { disclaimer: Setting.registry_whois_disclaimer, name: origin, + registered: created_at.try(:to_s, :iso8601), status: ['ok (paid and in zone)'], + changed: updated_at.try(:to_s, :iso8601), email: Setting.registry_email, + admin_contacts: [contact_vars], tech_contacts: [contact_vars], + nameservers: nameserver_vars } + end + + def registrar_vars + { registrar: Setting.registry_juridical_name, registrar_website: Setting.registry_url, + registrar_phone: Setting.registry_phone } + end + + def registrant_vars + { registrant: Setting.registry_juridical_name, registrant_reg_no: Setting.registry_reg_no, + registrant_ident_country_code: Setting.registry_country_code, registrant_kind: 'org', + registrant_disclosed_attributes: %w[name email] } + end + + def contact_vars + { name: Setting.registry_invoice_contact, email: Setting.registry_email, + disclosed_attributes: %w[name email] } + end + + def nameserver_vars + vars = [] + return vars unless ns_records + + parsed_ns = ns_records.gsub("\r", '').gsub("\n", '') + parsed_ns.split("#{origin}. IN NS ").each do |ns| + ns.delete_suffix! '.' + vars << ns if ns.match? Nameserver::HOSTNAME_REGEXP + end + + vars + end + end + end +end diff --git a/app/models/contact.rb b/app/models/contact.rb index 06407ae69..4199e6dc7 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -1,10 +1,13 @@ -class Contact < ActiveRecord::Base +require 'deserializers/xml/legal_document' + +class Contact < ApplicationRecord include Versions # version/contact_version.rb include EppErrors include UserEvents include Concerns::Contact::Transferable include Concerns::Contact::Identical include Concerns::Contact::Disclosable + include Concerns::EmailVerifable belongs_to :original, class_name: self.name belongs_to :registrar, required: true @@ -14,21 +17,25 @@ class Contact < ActiveRecord::Base has_many :registrant_domains, class_name: 'Domain', foreign_key: 'registrant_id' has_many :actions, dependent: :destroy - has_paper_trail class_name: "ContactVersion", meta: { children: :children_log } - attr_accessor :legal_document_id alias_attribute :kind, :ident_type alias_attribute :copy_from_id, :original_id # Old attribute name; for PaperTrail accepts_nested_attributes_for :legal_documents + scope :email_verification_failed, lambda { + joins('LEFT JOIN email_address_verifications emv ON contacts.email = emv.email') + .where('success = false and verified_at IS NOT NULL') + } + validates :name, :email, presence: true - validates :street, :city, :zip, :country_code, presence: true, if: 'self.class.address_processing?' + validates :street, :city, :zip, :country_code, presence: true, if: lambda { + self.class.address_processing? + } validates :phone, presence: true, e164: true, phone: true - validates :email, format: /@/ - validates :email, email_format: { message: :invalid }, if: proc { |c| c.email_changed? } + validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? } validates :code, uniqueness: { message: :epp_id_taken }, @@ -37,7 +44,7 @@ class Contact < ActiveRecord::Base validates_associated :identifier validate :validate_html - validate :validate_country_code, if: 'self.class.address_processing?' + validate :validate_country_code, if: -> { self.class.address_processing? } after_initialize do self.status_notes = {} if status_notes.nil? @@ -55,6 +62,9 @@ class Contact < ActiveRecord::Base mapping: [%w[ident code], %w[ident_type type], %w[ident_country_code country_code]] after_save :update_related_whois_records + before_validation :clear_address_modifications, if: -> { !self.class.address_processing? } + + self.ignored_columns = %w[legacy_id legacy_history_id] ORG = 'org' PRIV = 'priv' @@ -246,10 +256,8 @@ class Contact < ActiveRecord::Base end def registrant_user_contacts(registrant_user) - # In Rails 5, can be replaced with a much simpler `or` query method and the raw SQL parts can - # be removed. - from("(#{registrant_user_direct_contacts(registrant_user).to_sql} UNION " \ - "#{registrant_user_indirect_contacts(registrant_user).to_sql}) AS contacts") + registrant_user_direct_contacts(registrant_user) + .or(registrant_user_indirect_contacts(registrant_user)) end def registrant_user_direct_contacts(registrant_user) @@ -290,7 +298,7 @@ class Contact < ActiveRecord::Base end def to_s - name || '[no name]' + name end def validate_html @@ -351,7 +359,7 @@ class Contact < ActiveRecord::Base return false end - legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call if legal_document_data @@ -415,45 +423,65 @@ class Contact < ActiveRecord::Base # if total is smaller than needed, the load more # we also need to sort by valid_to # todo: extract to drapper. Then we can remove Domain#roles - def all_domains(page: nil, per: nil, params: {}) - # compose filter sql - filter_sql = case params[:domain_filter] - when "Registrant".freeze - %Q{select id from domains where registrant_id=#{id}} - when AdminDomainContact.to_s, TechDomainContact.to_s - %Q{select domain_id from domain_contacts where contact_id=#{id} AND type='#{params[:domain_filter]}'} - else - %Q{select domain_id from domain_contacts where contact_id=#{id} UNION select id from domains where registrant_id=#{id}} - end + def all_domains(page: nil, per: nil, params:, requester: nil) + filter_sql = qualified_domain_ids(params[:domain_filter]) # get sorting rules sorts = params.fetch(:sort, {}).first || [] - sort = Domain.column_names.include?(sorts.first) ? sorts.first : "valid_to" - order = {"asc"=>"desc", "desc"=>"asc"}[sorts.second] || "desc" - + sort = %w[name registrar_name valid_to].include?(sorts.first) ? sorts.first : 'valid_to' + order = %w[asc desc].include?(sorts.second) ? sorts.second : 'desc' # fetch domains - domains = Domain.where("domains.id IN (#{filter_sql})") + domains = qualified_domain_name_list(requester, filter_sql) domains = domains.includes(:registrar).page(page).per(per) - if sorts.first == "registrar_name".freeze - # using small rails hack to generate outer join - domains = domains.includes(:registrar).where.not(registrars: {id: nil}).order("registrars.name #{order} NULLS LAST") - else - domains = domains.order("#{sort} #{order} NULLS LAST") - end - - + # using small rails hack to generate outer join + domains = if sorts.first == 'registrar_name'.freeze + domains.includes(:registrar).where.not(registrars: { id: nil }) + .order("registrars.name #{order} NULLS LAST") + else + domains.order("#{sort} #{order} NULLS LAST") + end # adding roles. Need here to make faster sqls domain_c = Hash.new([]) - registrant_domains.where(id: domains.map(&:id)).each{|d| domain_c[d.id] |= ["Registrant".freeze] } - DomainContact.where(contact_id: id, domain_id: domains.map(&:id)).each{|d| domain_c[d.domain_id] |= [d.type] } - domains.each{|d| d.roles = domain_c[d.id].uniq} + registrant_domains.where(id: domains.map(&:id)).each do |d| + domain_c[d.id] |= ['Registrant'.freeze] + end + + DomainContact.where(contact_id: id, domain_id: domains.map(&:id)).each do |d| + domain_c[d.domain_id] |= [d.type] + end + + domains.each { |d| d.roles = domain_c[d.id].uniq } domains end + def qualified_domain_name_list(requester, filter_sql) + return Domain.where('domains.id IN (?)', filter_sql) if requester.blank? + + registrant_user = RegistrantUser.find_or_initialize_by(registrant_ident: + "#{requester.ident_country_code}-#{requester.ident}") + begin + registrant_user.domains.where('domains.id IN (?)', filter_sql) + rescue CompanyRegister::NotAvailableError + registrant_user.direct_domains.where('domains.id IN (?)', filter_sql) + end + end + + def qualified_domain_ids(domain_filter) + registrant_ids = registrant_domains.pluck(:id) + return registrant_ids if domain_filter == 'Registrant' + + if %w[AdminDomainContact TechDomainContact].include? domain_filter + DomainContact.select('domain_id').where(contact_id: id, type: domain_filter) + else + (DomainContact.select('domain_id').where(contact_id: id).pluck(:domain_id) + + registrant_ids).uniq + end + end + def update_prohibited? (statuses & [ CLIENT_UPDATE_PROHIBITED, @@ -480,9 +508,23 @@ class Contact < ActiveRecord::Base ]).present? end + def clear_address_modifications + return unless modifies_address? + + remove_address + end + + def modifies_address? + modified = false + self.class.address_attribute_names.each { |field| modified = true if changes.key?(field) } + + modified + end + def update_related_whois_records # not doing anything if no real changes - return if changes.slice(*(self.class.column_names - ["updated_at", "created_at", "statuses", "status_notes"])).empty? + ignored_columns = %w[updated_at created_at statuses status_notes] + return if saved_changes.slice(*(self.class.column_names - ignored_columns)).empty? names = related_domain_descriptions.keys UpdateWhoisRecordJob.enqueue(names, 'domain') if names.present? diff --git a/app/models/counter.rb b/app/models/counter.rb deleted file mode 100644 index 7d1c2b926..000000000 --- a/app/models/counter.rb +++ /dev/null @@ -1,24 +0,0 @@ -class Counter - def initialize value = 0 - @value = value - end - attr_accessor :value - def method_missing *args, &blk - @value.send(*args, &blk) - end - def to_s - @value.to_s - end - - def now - @value - end - - # pre-increment ".+" when x not present - def next(x = 1) - @value += x - end - def prev(x = 1) - @value -= x - end -end \ No newline at end of file diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index e2413a004..3bb3b7473 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -1,6 +1,7 @@ module Depp class Domain include ActiveModel::Conversion + include RemoveHold extend ActiveModel::Naming attr_accessor :name, :current_user, :epp_xml diff --git a/app/models/directo.rb b/app/models/directo.rb index f062912f9..a4af6c134 100644 --- a/app/models/directo.rb +++ b/app/models/directo.rb @@ -1,196 +1,3 @@ -class Directo < ActiveRecord::Base - DOMAIN_TO_PRODUCT = {"ee" => "01EE", "com.ee" => "02COM", "pri.ee" => "03PRI", "fie.ee"=>"04FIE", "med.ee" => "05MED"}.freeze +class Directo < ApplicationRecord belongs_to :item, polymorphic: true - - def self.send_receipts - new_trans = Invoice.where(in_directo: false).non_cancelled - total = new_trans.count - counter = 0 - Rails.logger.info("[DIRECTO] Will try to send #{total} invoices") - - new_trans.find_in_batches(batch_size: 10).each do |group| - mappers = {} # need them as no direct connection between invoice - builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml.invoices { - group.each do |invoice| - - if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || - invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.total - Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped") - next - end - counter += 1 - - num = invoice.number - mappers[num] = invoice - xml.invoice( - "SalesAgent" => Setting.directo_sales_agent, - "Number" => num, - "InvoiceDate" => invoice.issue_date.strftime("%Y-%m-%d"), - "PaymentTerm" => Setting.directo_receipt_payment_term, - "Currency" => invoice.currency, - "CustomerCode"=> invoice.buyer.accounting_customer_code - ){ - xml.line( - "ProductID" => Setting.directo_receipt_product_name, - "Quantity" => 1, - "UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.subtotal, precision: 2, separator: "."), - "ProductName" => invoice.order - ) - } - end - } - end - - data = builder.to_xml.gsub("\n",'') - Rails.logger.info("[Directo] XML request: #{data}") - response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false) - Rails.logger.info("[Directo] Directo responded with code: #{response.code}, body: #{response.body}") - dump_result_to_db(mappers, response.to_s) - end - - STDOUT << "#{Time.zone.now.utc} - Directo receipts sending finished. #{counter} of #{total} are sent\n" - end - - def self.dump_result_to_db mappers, xml - Nokogiri::XML(xml).css("Result").each do |res| - obj = mappers[res.attributes["docid"].value.to_i] - obj.directo_records.create!(response: res.as_json.to_h, invoice_number: obj.number) - obj.update_columns(in_directo: true) - Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") - end - end - - - def self.send_monthly_invoices(debug: false) - I18n.locale = :et - month = Time.now - 1.month - invoices_until = month.end_of_month - date_format = "%Y-%m-%d" - invoice_counter= Counter.new - - min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) - max_directo = Setting.directo_monthly_number_max.presence.try(:to_i) - last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i), min_directo].compact.max || 0 - if max_directo && max_directo <= last_directo - raise "Directo counter is out of period (max allowed number is smaller than last counter number)" - end - - directo_next = last_directo - Registrar.where.not(test_registrar: true).find_each do |registrar| - unless registrar.cash_account - Rails.logger.info("[DIRECTO] Monthly invoice for registrar #{registrar.id} has been skipped as it doesn't has cash_account") - next - end - counter = Counter.new(1) - items = {} - registrar_activities = AccountActivity.where(account_id: registrar.account_ids).where("created_at BETWEEN ? AND ?",month.beginning_of_month, month.end_of_month) - - # adding domains items - registrar_activities.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]).each do |activity| - price = load_price(activity) - - if price.duration.include?('year') - price.duration.to_i.times do |i| - year = i+1 - hash = { - "ProductID" => DOMAIN_TO_PRODUCT[price.zone_name], - "Unit" => "tk", - "ProductName" => ".#{price.zone_name} registreerimine: #{price.duration.to_i} aasta#{price.duration.to_i > 1 ? 't' : ''}", - "UnitPriceWoVAT" => price.price.amount / price.duration.to_i - } - hash["StartDate"] = (activity.created_at + (year-1).year).end_of_month.strftime(date_format) if year > 1 - hash["EndDate"] = (activity.created_at + (year-1).year + 1).end_of_month.strftime(date_format) if year > 1 - - if items.has_key?(hash) - items[hash]["Quantity"] += 1 - else - items[hash] = { "RN" => counter.next, "RR" => counter.now - i, "Quantity" => 1 } - end - end - else - 1.times do |i| - quantity = price.account_activities - .where(account_id: registrar.account_ids) - .where(created_at: month.beginning_of_month..month.end_of_month) - .where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]) - .count - - hash = { - "ProductID" => DOMAIN_TO_PRODUCT[price.zone_name], - "Unit" => "tk", - "ProductName" => ".#{price.zone_name} registreerimine: #{price.duration.to_i} kuud", - "UnitPriceWoVAT" => price.price.amount, - } - - if items.has_key?(hash) - #items[hash]["Quantity"] += 1 - else - items[hash] = { "RN" => counter.next, "RR" => counter.now - i, "Quantity" => quantity } - end - end - end - - - end - - #adding prepaiments - if items.any? - total = 0 - items.each{ |key, val| total += val["Quantity"] * key["UnitPriceWoVAT"] } - hash = {"ProductID" => Setting.directo_receipt_product_name, "Unit" => "tk", "ProductName" => "Domeenide ettemaks", "UnitPriceWoVAT"=>total} - items[hash] = {"RN"=>counter.next, "RR" => counter.now, "Quantity"=> -1} - end - - # generating XML - if items.any? - directo_next += 1 - invoice_counter.next - - builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml.invoices{ - xml.invoice("Number" =>directo_next, - "InvoiceDate" =>invoices_until.strftime(date_format), - "PaymentTerm" =>Setting.directo_receipt_payment_term, - "CustomerCode"=>registrar.accounting_customer_code, - "Language" =>"", - "Currency" =>registrar_activities.first.currency, - "SalesAgent" =>Setting.directo_sales_agent){ - xml.line("RN" => 1, "RR"=>1, "ProductName"=> "Domeenide registreerimine - #{I18n.l(invoices_until, format: "%B %Y").titleize}") - items.each do |line, val| - xml.line(val.merge(line)) - end - } - } - end - - data = builder.to_xml.gsub("\n",'') - Rails.logger.info("[Directo] XML request: #{data}") - - if debug - STDOUT << "#{Time.zone.now.utc} - Directo xml had to be sent #{data}\n" - else - response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false) - Rails.logger.info("[Directo] Directo responded with code: #{response.code}, body: #{response.body}") - response = response.to_s - - Setting.directo_monthly_number_last = directo_next - Nokogiri::XML(response).css("Result").each do |res| - Directo.create!(request: data, response: res.as_json.to_h, invoice_number: directo_next) - Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") - end - end - else - Rails.logger.info("[DIRECTO] Registrar #{registrar.id} has nothing to be sent to Directo") - end - - end - STDOUT << "#{Time.zone.now.utc} - Directo invoices sending finished. #{invoice_counter.now} are sent\n" - end - - def self.load_price(account_activity) - @pricelists ||= {} - return @pricelists[account_activity.price_id] if @pricelists.has_key?(account_activity.price_id) - @pricelists[account_activity.price_id] = account_activity.price - end end diff --git a/app/models/dispute.rb b/app/models/dispute.rb new file mode 100644 index 000000000..45ff27274 --- /dev/null +++ b/app/models/dispute.rb @@ -0,0 +1,133 @@ +class Dispute < ApplicationRecord + include WhoisStatusPopulate + validates :domain_name, :password, :starts_at, :expires_at, presence: true + before_validation :fill_empty_passwords, :set_expiry_date + validate :validate_domain_name_format + validate :validate_domain_name_period_uniqueness + validate :validate_start_date + + before_save :set_expiry_date, :sync_reserved_password, :generate_data + after_destroy :remove_data + + scope :expired, -> { where('expires_at < ?', Time.zone.today) } + scope :active, lambda { + where('starts_at <= ? AND expires_at >= ? AND closed IS NULL', Time.zone.today, Time.zone.today) + } + scope :closed, -> { where.not(closed: nil) } + + attr_readonly :domain_name + + def domain + Domain.find_by(name: domain_name) + end + + def self.close_by_domain(domain_name) + dispute = Dispute.active.find_by(domain_name: domain_name) + return false unless dispute + + dispute.close(initiator: 'Registrant') + end + + def self.valid_auth?(domain_name, password) + Dispute.active.find_by(domain_name: domain_name, password: password).present? + end + + def set_expiry_date + return if starts_at.blank? + + self.expires_at = starts_at + Setting.dispute_period_in_months.months + end + + def generate_password + self.password = SecureRandom.hex + end + + def generate_data + return if starts_at > Time.zone.today || expires_at < Time.zone.today + + domain&.mark_as_disputed + return if domain + + wr = Whois::Record.find_or_initialize_by(name: domain_name) + wr.json = @json = generate_json(wr, domain_status: 'disputed') + wr.save + end + + def close(initiator: 'Unknown') + return false unless update(closed: Time.zone.now, initiator: initiator) + return if Dispute.active.where(domain_name: domain_name).any? + + domain&.unmark_as_disputed + return true if domain + + forward_to_auction_if_possible + end + + def forward_to_auction_if_possible + domain = DNS::DomainName.new(domain_name) + if domain.available? && domain.auctionable? + domain.sell_at_auction + return true + end + + whois_record = Whois::Record.find_by(name: domain_name) + remove_whois_data(whois_record) + end + + def remove_whois_data(record) + return true unless record + + record.json['status'] = record.json['status'].delete_if { |status| status == 'disputed' } + record.destroy && return if record.json['status'].blank? + + record.save + end + + def remove_data + UpdateWhoisRecordJob.enqueue domain_name, 'disputed' + end + + def fill_empty_passwords + generate_password if password.blank? + end + + def sync_reserved_password + reserved_domain = ReservedDomain.find_by(name: domain_name) + generate_password if password.blank? + + unless reserved_domain.nil? + reserved_domain.password = password + reserved_domain.save! + end + + generate_data + end + + private + + def validate_start_date + return if starts_at.nil? + + errors.add(:starts_at, :future) if starts_at.future? + end + + def validate_domain_name_format + return unless domain_name + + zone = domain_name.reverse.rpartition('.').map(&:reverse).reverse.last + supported_zone = DNS::Zone.origins.include?(zone) + + errors.add(:domain_name, :unsupported_zone) unless supported_zone + end + + def validate_domain_name_period_uniqueness + existing_dispute = Dispute.unscoped.where(domain_name: domain_name, closed: nil) + .where('expires_at >= ?', starts_at) + + existing_dispute = existing_dispute.where.not(id: id) unless new_record? + + return unless existing_dispute.any? + + errors.add(:starts_at, 'Dispute already exists for this domain at given timeframe') + end +end diff --git a/app/models/dns/domain_name.rb b/app/models/dns/domain_name.rb index d2ca9fa50..c1af4d5e7 100644 --- a/app/models/dns/domain_name.rb +++ b/app/models/dns/domain_name.rb @@ -60,13 +60,18 @@ module DNS end def blocked? - BlockedDomain.where(name: name).any? + BlockedDomain.where(name: name).any? || + BlockedDomain.where(name: SimpleIDN.to_unicode(name)).any? end def reserved? ReservedDomain.where(name: name).any? end + def disputed? + Dispute.active.where(domain_name: name).any? + end + def auctionable? !not_auctionable? end @@ -80,7 +85,7 @@ module DNS attr_reader :name def not_auctionable? - blocked? || reserved? + blocked? || reserved? || disputed? end def zone_with_same_origin? diff --git a/app/models/dns/zone.rb b/app/models/dns/zone.rb index a63d9b280..31749d952 100644 --- a/app/models/dns/zone.rb +++ b/app/models/dns/zone.rb @@ -1,11 +1,14 @@ +# frozen_string_literal: true + module DNS - class Zone < ActiveRecord::Base + class Zone < ApplicationRecord validates :origin, :ttl, :refresh, :retry, :expire, :minimum_ttl, :email, :master_nameserver, presence: true validates :ttl, :refresh, :retry, :expire, :minimum_ttl, numericality: { only_integer: true } validates :origin, uniqueness: true + include Concerns::Zone::WhoisQueryable before_destroy do - !used? + throw(:abort) if used? end def self.generate_zonefiles diff --git a/app/models/dnskey.rb b/app/models/dnskey.rb index 02b43d729..c0f3f7491 100644 --- a/app/models/dnskey.rb +++ b/app/models/dnskey.rb @@ -1,4 +1,4 @@ -class Dnskey < ActiveRecord::Base +class Dnskey < ApplicationRecord include Versions # version/dnskey_version.rb include EppErrors @@ -9,10 +9,16 @@ class Dnskey < ActiveRecord::Base validate :validate_protocol validate :validate_flags - before_save -> { generate_digest if public_key_changed? && !ds_digest_changed? } + before_save lambda { + generate_digest if will_save_change_to_public_key? && !will_save_change_to_ds_digest? + } before_save lambda { - if (public_key_changed? || flags_changed? || alg_changed? || protocol_changed?) && !ds_key_tag_changed? + if (will_save_change_to_public_key? || + will_save_change_to_flags? || + will_save_change_to_alg? || + will_save_change_to_protocol?) && + !will_save_change_to_ds_key_tag? generate_ds_key_tag end } @@ -22,6 +28,8 @@ class Dnskey < ActiveRecord::Base FLAGS = %w(0 256 257) # 256 = ZSK, 257 = KSK DS_DIGEST_TYPE = [1,2] + self.ignored_columns = %w[legacy_domain_id] + def epp_code_map { '2005' => [ diff --git a/app/models/domain.rb b/app/models/domain.rb index cce1c9f41..fff0d4a08 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -1,4 +1,4 @@ -class Domain < ActiveRecord::Base +class Domain < ApplicationRecord include UserEvents include Versions # version/domain_version.rb include Concerns::Domain::Expirable @@ -9,8 +9,7 @@ class Domain < ActiveRecord::Base include Concerns::Domain::Transferable include Concerns::Domain::RegistryLockable include Concerns::Domain::Releasable - - has_paper_trail class_name: "DomainVersion", meta: { children: :children_log } + include Concerns::Domain::Disputable attr_accessor :roles @@ -57,6 +56,7 @@ class Domain < ActiveRecord::Base has_many :legal_documents, as: :documentable accepts_nested_attributes_for :legal_documents, reject_if: proc { |attrs| attrs[:body].blank? } + has_many :registrant_verifications, dependent: :destroy after_initialize do self.pending_json = {} if pending_json.blank? @@ -72,12 +72,13 @@ class Domain < ActiveRecord::Base before_update :manage_statuses def manage_statuses - return unless registrant_id_changed? # rollback has not yet happened + return unless will_save_change_to_registrant_id? # rollback has not yet happened + pending_update! if registrant_verification_asked? true end - after_commit :update_whois_record, unless: 'domain_name.at_auction?' + after_commit :update_whois_record, unless: -> { domain_name.at_auction? } after_create :update_reserved_domains def update_reserved_domains @@ -88,8 +89,8 @@ class Domain < ActiveRecord::Base validates :puny_label, length: { maximum: 63 } validates :period, presence: true, numericality: { only_integer: true } validates :transfer_code, presence: true - validate :validate_reservation + def validate_reservation return if persisted? || !in_reserved_list? @@ -99,6 +100,7 @@ class Domain < ActiveRecord::Base end return if ReservedDomain.pw_for(name) == reserved_pw + errors.add(:base, :invalid_auth_information_reserved) end @@ -115,12 +117,15 @@ class Domain < ActiveRecord::Base attr_accessor :is_admin - validate :check_permissions, :unless => :is_admin - def check_permissions - return unless force_delete_scheduled? - errors.add(:base, I18n.t(:object_status_prohibits_operation)) - false - end + # Removed to comply new ForceDelete procedure + # at https://github.com/internetee/registry/issues/1428#issuecomment-570561967 + # + # validate :check_permissions, :unless => :is_admin + # def check_permissions + # return unless force_delete_scheduled? + # errors.add(:base, I18n.t(:object_status_prohibits_operation)) + # false + # end validates :nameservers, domain_nameserver: { min: -> { Setting.ns_min_count }, @@ -169,6 +174,8 @@ class Domain < ActiveRecord::Base attr_accessor :registrant_typeahead, :update_me, :epp_pending_update, :epp_pending_delete, :reserved_pw + self.ignored_columns = %w[legacy_id legacy_registrar_id legacy_registrant_id] + def subordinate_nameservers nameservers.select { |x| x.hostname.end_with?(name) } end @@ -191,8 +198,6 @@ class Domain < ActiveRecord::Base end def registrant_user_domains(registrant_user) - # In Rails 5, can be replaced with a much simpler `or` query method and the raw SQL parts can - # be removed. from( "(#{registrant_user_domains_by_registrant(registrant_user).to_sql} UNION " \ "#{registrant_user_domains_by_contact(registrant_user).to_sql}) AS domains" @@ -200,8 +205,6 @@ class Domain < ActiveRecord::Base end def registrant_user_direct_domains(registrant_user) - # In Rails 5, can be replaced with a much simpler `or` query method and the raw SQL parts can - # be removed. from( "(#{registrant_user_direct_domains_by_registrant(registrant_user).to_sql} UNION " \ "#{registrant_user_direct_domains_by_contact(registrant_user).to_sql}) AS domains" @@ -209,8 +212,6 @@ class Domain < ActiveRecord::Base end def registrant_user_administered_domains(registrant_user) - # In Rails 5, can be replaced with a much simpler `or` query method and the raw SQL parts can - # be removed. from( "(#{registrant_user_domains_by_registrant(registrant_user).to_sql} UNION " \ "#{registrant_user_domains_by_admin_contact(registrant_user).to_sql}) AS domains" @@ -229,7 +230,7 @@ class Domain < ActiveRecord::Base def registrant_user_domains_by_admin_contact(registrant_user) joins(:domain_contacts).where(domain_contacts: { contact_id: registrant_user.contacts, - type: [AdminDomainContact] }) + type: [AdminDomainContact.name] }) end def registrant_user_direct_domains_by_registrant(registrant_user) @@ -283,20 +284,23 @@ class Domain < ActiveRecord::Base def server_holdable? return false if statuses.include?(DomainStatus::SERVER_HOLD) return false if statuses.include?(DomainStatus::SERVER_MANUAL_INZONE) + true end def renewable? - if Setting.days_to_renew_domain_before_expire != 0 - # if you can renew domain at days_to_renew before domain expiration - if (expire_time.to_date - Date.today) + 1 > Setting.days_to_renew_domain_before_expire - return false - end + blocking_statuses = [DomainStatus::DELETE_CANDIDATE, DomainStatus::PENDING_RENEW, + DomainStatus::PENDING_TRANSFER, DomainStatus::DISPUTED, + DomainStatus::PENDING_UPDATE, DomainStatus::PENDING_DELETE, + DomainStatus::PENDING_DELETE_CONFIRMATION] + return false if statuses.include_any? blocking_statuses + return true unless Setting.days_to_renew_domain_before_expire != 0 + + # if you can renew domain at days_to_renew before domain expiration + if (expire_time.to_date - Time.zone.today) + 1 > Setting.days_to_renew_domain_before_expire + return false end - return false if statuses.include_any?(DomainStatus::DELETE_CANDIDATE, DomainStatus::PENDING_RENEW, - DomainStatus::PENDING_TRANSFER, DomainStatus::PENDING_DELETE, - DomainStatus::PENDING_UPDATE, DomainStatus::PENDING_DELETE_CONFIRMATION) true end @@ -486,9 +490,9 @@ class Domain < ActiveRecord::Base self.delete_date = nil when DomainStatus::SERVER_MANUAL_INZONE # removal causes server hold to set self.outzone_at = Time.zone.now if force_delete_scheduled? - when DomainStatus::DomainStatus::EXPIRED # removal causes server hold to set + when DomainStatus::EXPIRED # removal causes server hold to set self.outzone_at = self.expire_time + 15.day - when DomainStatus::DomainStatus::SERVER_HOLD # removal causes server hold to set + when DomainStatus::SERVER_HOLD # removal causes server hold to set self.outzone_at = nil end end @@ -547,6 +551,8 @@ class Domain < ActiveRecord::Base activate if nameservers.reject(&:marked_for_destruction?).size >= Setting.ns_min_count end + cancel_force_delete if force_delete_scheduled? && will_save_change_to_registrant_id? + if statuses.empty? && valid? statuses << DomainStatus::OK elsif (statuses.length > 1 && active?) || !valid? @@ -585,6 +591,15 @@ class Domain < ActiveRecord::Base (admin_contacts.emails + [registrant.email]).uniq end + def force_delete_contact_emails + (primary_contact_emails + tech_contacts.pluck(:email) + + ["info@#{name}", "#{prepared_domain_name}@#{name}"]).uniq + end + + def prepared_domain_name + name.split('.')&.first + end + def new_registrant_email pending_json['new_registrant_email'] end diff --git a/app/models/domain_contact.rb b/app/models/domain_contact.rb index b433cd3dc..910f4e445 100644 --- a/app/models/domain_contact.rb +++ b/app/models/domain_contact.rb @@ -1,4 +1,4 @@ -class DomainContact < ActiveRecord::Base +class DomainContact < ApplicationRecord # STI: tech_domain_contact # STI: admin_domain_contact include Versions # version/domain_contact_version.rb @@ -8,6 +8,8 @@ class DomainContact < ActiveRecord::Base attr_accessor :value_typeahead + self.ignored_columns = %w[legacy_domain_id legacy_contact_id] + def epp_code_map { '2302' => [ diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index 578538e17..ad64456ca 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -1,9 +1,12 @@ class DomainCron + include Concerns::Job::ForceDelete + include Concerns::Job::ForceDeleteLogging + include Concerns::Job::ForceDeleteNotify def self.clean_expired_pendings STDOUT << "#{Time.zone.now.utc} - Clean expired domain pendings\n" unless Rails.env.test? - ::PaperTrail.whodunnit = "cron - #{__method__}" + ::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) @@ -35,7 +38,7 @@ class DomainCron end def self.start_expire_period - ::PaperTrail.whodunnit = "cron - #{__method__}" + ::PaperTrail.request.whodunnit = "cron - #{__method__}" domains = Domain.expired marked = 0 real = 0 @@ -61,7 +64,7 @@ class DomainCron def self.start_redemption_grace_period STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test? - ::PaperTrail.whodunnit = "cron - #{__method__}" + ::PaperTrail.request.whodunnit = "cron - #{__method__}" domains = Domain.outzone_candidates marked = 0 diff --git a/app/models/domain_status.rb b/app/models/domain_status.rb index 151ecb0ee..bf0ae2a51 100644 --- a/app/models/domain_status.rb +++ b/app/models/domain_status.rb @@ -1,7 +1,7 @@ -class DomainStatus < ActiveRecord::Base - include Versions # version/domain_status_version.rb - include EppErrors +# frozen_string_literal: true +class DomainStatus < ApplicationRecord + include EppErrors belongs_to :domain # Requests to delete the object MUST be rejected. @@ -72,6 +72,7 @@ class DomainStatus < ActiveRecord::Base FORCE_DELETE = 'serverForceDelete' DELETE_CANDIDATE = 'deleteCandidate' EXPIRED = 'expired' + DISPUTED = 'disputed' STATUSES = [ CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED, CLIENT_HOLD, SERVER_HOLD, @@ -80,19 +81,19 @@ class DomainStatus < ActiveRecord::Base INACTIVE, OK, PENDING_CREATE, PENDING_DELETE, PENDING_DELETE_CONFIRMATION, PENDING_RENEW, PENDING_TRANSFER, PENDING_UPDATE, SERVER_MANUAL_INZONE, SERVER_REGISTRANT_CHANGE_PROHIBITED, SERVER_ADMIN_CHANGE_PROHIBITED, SERVER_TECH_CHANGE_PROHIBITED, FORCE_DELETE, - DELETE_CANDIDATE, EXPIRED - ] + DELETE_CANDIDATE, EXPIRED, DISPUTED + ].freeze CLIENT_STATUSES = [ CLIENT_DELETE_PROHIBITED, CLIENT_HOLD, CLIENT_RENEW_PROHIBITED, CLIENT_TRANSFER_PROHIBITED, CLIENT_UPDATE_PROHIBITED - ] + ].freeze SERVER_STATUSES = [ SERVER_DELETE_PROHIBITED, SERVER_HOLD, SERVER_RENEW_PROHIBITED, SERVER_TRANSFER_PROHIBITED, SERVER_UPDATE_PROHIBITED, SERVER_MANUAL_INZONE, SERVER_REGISTRANT_CHANGE_PROHIBITED, SERVER_ADMIN_CHANGE_PROHIBITED, SERVER_TECH_CHANGE_PROHIBITED - ] + ].freeze UPDATE_PROHIBIT_STATES = [ DomainStatus::PENDING_DELETE_CONFIRMATION, diff --git a/app/models/domain_transfer.rb b/app/models/domain_transfer.rb index 91cdb2d67..02ab2bc88 100644 --- a/app/models/domain_transfer.rb +++ b/app/models/domain_transfer.rb @@ -1,4 +1,4 @@ -class DomainTransfer < ActiveRecord::Base +class DomainTransfer < ApplicationRecord belongs_to :domain belongs_to :old_registrar, class_name: 'Registrar' diff --git a/app/models/email_address_verification.rb b/app/models/email_address_verification.rb new file mode 100644 index 000000000..2fe7c0dbe --- /dev/null +++ b/app/models/email_address_verification.rb @@ -0,0 +1,56 @@ +class EmailAddressVerification < ApplicationRecord + RECENTLY_VERIFIED_PERIOD = 1.month + + scope :not_verified_recently, lambda { + where('verified_at IS NULL or verified_at < ?', verification_period) + } + + scope :verified_recently, lambda { + where('verified_at IS NOT NULL and verified_at >= ?', verification_period).where(success: true) + } + + scope :verification_failed, lambda { + where.not(verified_at: nil).where(success: false) + } + + scope :by_domain, ->(domain_name) { where(domain: domain_name) } + + def recently_verified? + verified_at.present? && + verified_at > verification_period + end + + def verification_period + self.class.verification_period + end + + def self.verification_period + Time.zone.now - RECENTLY_VERIFIED_PERIOD + end + + def not_verified? + verified_at.blank? && !success + end + + def failed? + verified_at.present? && !success + end + + def verified? + success + end + + def verify + validation_request = Truemail.validate(email) + + if validation_request.result.success + update(verified_at: Time.zone.now, + success: true) + else + update(verified_at: Time.zone.now, + success: false) + end + + validation_request.result + end +end diff --git a/app/models/epp/contact.rb b/app/models/epp/contact.rb index 8ea01b67d..6867b037d 100644 --- a/app/models/epp/contact.rb +++ b/app/models/epp/contact.rb @@ -1,3 +1,7 @@ +require 'deserializers/xml/legal_document' +require 'deserializers/xml/ident' +require 'deserializers/xml/contact' + class Epp::Contact < Contact include EppErrors @@ -9,7 +13,7 @@ class Epp::Contact < Contact def manage_permissions return unless update_prohibited? || delete_prohibited? add_epp_error('2304', nil, nil, I18n.t(:object_status_prohibits_operation)) - false + throw(:abort) end class << self @@ -20,26 +24,9 @@ class Epp::Contact < Contact end def attrs_from(frame, new_record: false) - f = frame - at = {}.with_indifferent_access - at[:name] = f.css('postalInfo name').text if f.css('postalInfo name').present? - at[:org_name] = f.css('postalInfo org').text if f.css('postalInfo org').present? - at[:email] = f.css('email').text if f.css('email').present? - at[:fax] = f.css('fax').text if f.css('fax').present? - at[:phone] = f.css('voice').text if f.css('voice').present? - - if address_processing? - at[:city] = f.css('postalInfo addr city').text if f.css('postalInfo addr city').present? - at[:zip] = f.css('postalInfo addr pc').text if f.css('postalInfo addr pc').present? - at[:street] = f.css('postalInfo addr street').text if f.css('postalInfo addr street').present? - at[:state] = f.css('postalInfo addr sp').text if f.css('postalInfo addr sp').present? - at[:country_code] = f.css('postalInfo addr cc').text if f.css('postalInfo addr cc').present? - end - - at[:auth_info] = f.css('authInfo pw').text if f.css('authInfo pw').present? - - - at.merge!(ident_attrs(f.css('ident').first)) if new_record + at = ::Deserializers::Xml::Contact.new(frame).call + ident_attrs = ::Deserializers::Xml::Ident.new(frame).call + at.merge!(ident_attrs) if new_record at end @@ -54,36 +41,6 @@ class Epp::Contact < Contact ) end - def ident_attrs(ident_frame) - return {} unless ident_attr_valid?(ident_frame) - - { - ident: ident_frame.text, - ident_type: ident_frame.attr('type'), - ident_country_code: ident_frame.attr('cc') - } - end - - def ident_attr_valid?(ident_frame) - return false if ident_frame.blank? - return false if ident_frame.try('text').blank? - return false if ident_frame.attr('type').blank? - return false if ident_frame.attr('cc').blank? - - true - end - - def legal_document_attrs(legal_frame) - return [] if legal_frame.blank? - return [] if legal_frame.try('text').blank? - return [] if legal_frame.attr('type').blank? - - [{ - body: legal_frame.text, - document_type: legal_frame.attr('type') - }] - end - def check_availability(codes) codes = [codes] if codes.is_a?(String) @@ -99,10 +56,11 @@ class Epp::Contact < Contact res end - end + delegate :ident_attr_valid?, to: :class + # rubocop:disable Style/SymbolArray def epp_code_map { '2003' => [ # Required parameter missing @@ -120,7 +78,10 @@ class Epp::Contact < Contact [:email, :invalid], [:country_code, :invalid], [:code, :invalid], - [:code, :too_long_contact_code] + [:code, :too_long_contact_code], + [:email, :email_smtp_check_error], + [:email, :email_mx_check_error], + [:email, :email_regex_check_error], ], '2302' => [ # Object exists [:code, :epp_id_taken] @@ -130,102 +91,7 @@ class Epp::Contact < Contact ] } end - - def update_attributes(frame, current_user) - return super if frame.blank? - at = {}.with_indifferent_access - at.deep_merge!(self.class.attrs_from(frame.css('chg'), new_record: false)) - - if Setting.client_status_editing_enabled - at[:statuses] = statuses - statuses_attrs(frame.css('rem'), 'rem') + statuses_attrs(frame.css('add'), 'add') - end - - if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) - frame.css("legalDocument").first.content = doc.path if doc&.persisted? - self.legal_document_id = doc.id - end - - ident_frame = frame.css('ident').first - - # https://github.com/internetee/registry/issues/576 - if ident_frame - if identifier.valid? - submitted_ident = Ident.new(code: ident_frame.text, - type: ident_frame.attr('type'), - country_code: ident_frame.attr('cc')) - - if submitted_ident != identifier - add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident')) - return - end - else - ident_update_attempt = ident_frame.text.present? && (ident_frame.text != ident) - - if ident_update_attempt - add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.ident_update')) - return - end - - identifier = Ident.new(code: ident, - type: ident_frame.attr('type'), - country_code: ident_frame.attr('cc')) - - identifier.validate - - self.identifier = identifier - self.ident_updated_at ||= Time.zone.now - end - end - - self.upid = current_user.registrar.id if current_user.registrar - self.up_date = Time.zone.now - - self.attributes = at - - email_changed = email_changed? - old_email = email_was - updated = save - - if updated && email_changed && registrant? - ContactMailer.email_changed(contact: self, old_email: old_email).deliver_now - end - - updated - end - - def statuses_attrs(frame, action) - status_list = status_list_from(frame) - - if action == 'rem' - to_destroy = [] - status_list.each do |status| - if statuses.include?(status) - to_destroy << status - else - add_epp_error('2303', 'status', status, [:contact_statuses, :not_found]) - end - end - - return to_destroy - else - return status_list - end - end - - def status_list_from(frame) - status_list = [] - - frame.css('status').each do |status| - unless Contact::CLIENT_STATUSES.include?(status['s']) - add_epp_error('2303', 'status', status['s'], [:domain_statuses, :not_found]) - next - end - - status_list << status['s'] - end - - status_list - end + # rubocop:enable Style/SymbolArray def attach_legal_document(legal_document_data) return unless legal_document_data @@ -237,7 +103,7 @@ class Epp::Contact < Contact end def add_legal_file_to_new frame - legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call return unless legal_document_data doc = LegalDocument.create( diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index dc5de8d61..a6fe58c71 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -1,3 +1,5 @@ +require 'deserializers/xml/legal_document' + class Epp::Domain < Domain include EppErrors @@ -9,10 +11,11 @@ class Epp::Domain < Domain def manage_permissions return if is_admin # this bad hack for 109086524, refactor later return true if is_transfer || is_renewal - return unless update_prohibited? || delete_prohibited? + return unless update_prohibited? + stat = (statuses & (DomainStatus::UPDATE_PROHIBIT_STATES + DomainStatus::DELETE_PROHIBIT_STATES)).first add_epp_error('2304', 'status', stat, I18n.t(:object_status_prohibits_operation)) - false + throw(:abort) end after_validation :validate_contacts @@ -52,12 +55,13 @@ class Epp::Domain < Domain def epp_code_map { '2002' => [ # Command use error - [:base, :domain_already_belongs_to_the_querying_registrar] + %i[base domain_already_belongs_to_the_querying_registrar], ], '2003' => [ # Required parameter missing - [:registrant, :blank], - [:registrar, :blank], - [:base, :required_parameter_missing_reserved] + %i[registrant blank], + %i[registrar blank], + %i[base required_parameter_missing_reserved], + %i[base required_parameter_missing_disputed], ], '2004' => [ # Parameter value range error [:dnskeys, :out_of_range, @@ -84,10 +88,11 @@ class Epp::Domain < Domain [:puny_label, :too_long, { obj: 'name', val: name_puny }] ], '2201' => [ # Authorisation error - [:transfer_code, :wrong_pw] + %i[transfer_code wrong_pw], ], '2202' => [ - [:base, :invalid_auth_information_reserved] + %i[base invalid_auth_information_reserved], + %i[base invalid_auth_information_disputed], ], '2302' => [ # Object exists [:name_dirty, :taken, { value: { obj: 'name', val: name_dirty } }], @@ -177,14 +182,12 @@ class Epp::Domain < Domain # Adding legal doc to domain and # if something goes wrong - raise Rollback error def add_legal_file_to_new frame - legal_document_data = Epp::Domain.parse_legal_document_from_frame(frame) + legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call return unless legal_document_data + return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir']) - doc = LegalDocument.create( - documentable_type: Domain, - document_type: legal_document_data[:type], - body: legal_document_data[:body] - ) + doc = LegalDocument.create(documentable_type: Domain, document_type: legal_document_data[:type], + body: legal_document_data[:body]) self.legal_documents = [doc] frame.css("legalDocument").first.content = doc.path if doc&.persisted? @@ -454,7 +457,7 @@ class Epp::Domain < Domain at.deep_merge!(attrs_from(frame.css('chg'), current_user, 'chg')) at.deep_merge!(attrs_from(frame.css('rem'), current_user, 'rem')) - if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) + if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) frame.css("legalDocument").first.content = doc.path if doc&.persisted? self.legal_document_id = doc.id end @@ -472,13 +475,36 @@ class Epp::Domain < Domain self.up_date = Time.zone.now end - same_registrant_as_current = (registrant.code == frame.css('registrant').text) + registrant_verification_needed = false + # registrant block may not be present, so we need this to rule out false positives + if frame.css('registrant').text.present? + registrant_verification_needed = (registrant.code != frame.css('registrant').text) + end - if !same_registrant_as_current && errors.empty? && verify && + if registrant_verification_needed && disputed? + disputed_pw = frame.css('reserved > pw').text + if disputed_pw.blank? + add_epp_error('2304', nil, nil, 'Required parameter missing; reserved' \ + 'pw element required for dispute domains') + else + dispute = Dispute.active.find_by(domain_name: name, password: disputed_pw) + if dispute + Dispute.close_by_domain(name) + registrant_verification_needed = false # Prevent asking current registrant confirmation + else + add_epp_error('2202', nil, nil, 'Invalid authorization information; '\ + 'invalid reserved>pw value') + end + end + end + + unverified_registrant_params = frame.css('registrant').present? && + frame.css('registrant').attr('verified').to_s.downcase != 'yes' + + if registrant_verification_needed && errors.empty? && verify && Setting.request_confrimation_on_registrant_change_enabled && - frame.css('registrant').present? && - frame.css('registrant').attr('verified').to_s.downcase != 'yes' - registrant_verification_asked!(frame.to_s, current_user.id) + unverified_registrant_params + registrant_verification_asked!(frame.to_s, current_user.id) unless disputed? end errors.empty? && super(at) @@ -515,6 +541,7 @@ class Epp::Domain < Domain def attach_legal_document(legal_document_data) return unless legal_document_data + return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir']) legal_documents.create( document_type: legal_document_data[:type], @@ -528,7 +555,7 @@ class Epp::Domain < Domain return end - if doc = attach_legal_document(Epp::Domain.parse_legal_document_from_frame(frame)) + if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) frame.css("legalDocument").first.content = doc.path if doc&.persisted? end @@ -639,7 +666,7 @@ class Epp::Domain < Domain self.registrar = current_user.registrar end - attach_legal_document(self.class.parse_legal_document_from_frame(frame)) + attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) save!(validate: false) return dt @@ -664,7 +691,7 @@ class Epp::Domain < Domain regenerate_transfer_code self.registrar = pt.new_registrar - attach_legal_document(self.class.parse_legal_document_from_frame(frame)) + attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) save!(validate: false) end @@ -684,7 +711,7 @@ class Epp::Domain < Domain status: DomainTransfer::CLIENT_REJECTED ) - attach_legal_document(self.class.parse_legal_document_from_frame(frame)) + attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call) save!(validate: false) end @@ -705,6 +732,11 @@ class Epp::Domain < Domain def can_be_deleted? + if disputed? + errors.add(:base, :domain_status_prohibits_operation) + return false + end + begin errors.add(:base, :domain_status_prohibits_operation) return false @@ -728,18 +760,6 @@ class Epp::Domain < Domain p[:unit] end - def parse_legal_document_from_frame(parsed_frame) - ld = parsed_frame.css('legalDocument').first - return nil unless ld - return nil if ld.text.starts_with?(ENV['legal_documents_dir']) # escape reloading - return nil if ld.text.starts_with?('/home/') # escape reloading - - { - body: ld.text, - type: ld['type'] - } - end - def check_availability(domain_names) domain_names = [domain_names] if domain_names.is_a?(String) diff --git a/app/models/epp/response/result/code.rb b/app/models/epp/response/result/code.rb index 2a65f6747..1be4a3f7c 100644 --- a/app/models/epp/response/result/code.rb +++ b/app/models/epp/response/result/code.rb @@ -7,6 +7,7 @@ module Epp KEY_TO_VALUE = { completed_successfully: 1000, completed_successfully_action_pending: 1001, + completed_without_address: 1100, completed_successfully_no_messages: 1300, completed_successfully_ack_to_dequeue: 1301, completed_successfully_ending_session: 1500, @@ -35,6 +36,7 @@ module Epp DEFAULT_DESCRIPTIONS = { 1000 => 'Command completed successfully', 1001 => 'Command completed successfully; action pending', + 1100 => 'Command completed successfully; Postal address data discarded', 1300 => 'Command completed successfully; no messages', 1301 => 'Command completed successfully; ack to dequeue', 1500 => 'Command completed successfully; ending session', diff --git a/app/models/epp_session.rb b/app/models/epp_session.rb index dfd603fc4..6427c503c 100644 --- a/app/models/epp_session.rb +++ b/app/models/epp_session.rb @@ -1,4 +1,4 @@ -class EppSession < ActiveRecord::Base +class EppSession < ApplicationRecord belongs_to :user, required: true validates :session_id, uniqueness: true, presence: true diff --git a/app/models/invoice.rb b/app/models/invoice.rb index cde439c70..a130a90ff 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -1,12 +1,14 @@ -class Invoice < ActiveRecord::Base +class Invoice < ApplicationRecord include Versions include Concerns::Invoice::Cancellable include Concerns::Invoice::Payable + include Concerns::Invoice::BookKeeping belongs_to :buyer, class_name: 'Registrar' has_one :account_activity has_many :items, class_name: 'InvoiceItem', dependent: :destroy has_many :directo_records, as: :item, class_name: 'Directo' + has_many :payment_orders accepts_nested_attributes_for :items @@ -47,7 +49,7 @@ class Invoice < ActiveRecord::Base errors.add(:base, I18n.t('failed_to_generate_invoice_invoice_number_limit_reached')) logger.error('INVOICE NUMBER LIMIT REACHED, COULD NOT GENERATE INVOICE') - false + throw(:abort) end def to_s @@ -70,7 +72,7 @@ class Invoice < ActiveRecord::Base Country.new(buyer_country_code) end -# order is used for directo/banklink description + # order is used for directo/banklink description def order "Order nr. #{number}" end @@ -102,6 +104,14 @@ class Invoice < ActiveRecord::Base generator.generate end + def do_not_send_e_invoice? + e_invoice_sent? || cancelled? || paid? + end + + def e_invoice_sent? + e_invoice_sent_at.present? + end + private def apply_default_buyer_vat_no @@ -111,4 +121,4 @@ class Invoice < ActiveRecord::Base def calculate_total self.total = subtotal + vat_amount end -end \ No newline at end of file +end diff --git a/app/models/invoice_item.rb b/app/models/invoice_item.rb index 6efd7b829..ec0c77767 100644 --- a/app/models/invoice_item.rb +++ b/app/models/invoice_item.rb @@ -1,4 +1,4 @@ -class InvoiceItem < ActiveRecord::Base +class InvoiceItem < ApplicationRecord include Versions belongs_to :invoice diff --git a/app/models/legal_document.rb b/app/models/legal_document.rb index 630c52d98..446087124 100644 --- a/app/models/legal_document.rb +++ b/app/models/legal_document.rb @@ -1,4 +1,4 @@ -class LegalDocument < ActiveRecord::Base +class LegalDocument < ApplicationRecord cattr_accessor :explicitly_write_file include EppErrors MIN_BODY_SIZE = (1.37 * 3.kilobytes).ceil @@ -14,8 +14,7 @@ class LegalDocument < ActiveRecord::Base belongs_to :documentable, polymorphic: true - - validate :val_body_length, if: ->(file){ file.path.blank? && !Rails.env.staging?} + validate :val_body_length, if: ->(file) { file.path.blank? } before_create :add_creator before_save :save_to_filesystem, if: :body @@ -32,7 +31,6 @@ class LegalDocument < ActiveRecord::Base errors.add(:body, :length) if body.nil? || body.size < MIN_BODY_SIZE end - def save_to_filesystem binary = Base64.decode64(body) digest = Digest::SHA1.new.update(binary).to_s @@ -58,7 +56,7 @@ class LegalDocument < ActiveRecord::Base end def add_creator - self.creator_str = ::PaperTrail.whodunnit + self.creator_str = ::PaperTrail.request.whodunnit true end diff --git a/app/models/nameserver.rb b/app/models/nameserver.rb index 4a0361397..3e4051165 100644 --- a/app/models/nameserver.rb +++ b/app/models/nameserver.rb @@ -1,4 +1,4 @@ -class Nameserver < ActiveRecord::Base +class Nameserver < ApplicationRecord include Versions # version/nameserver_version.rb include EppErrors @@ -34,6 +34,8 @@ class Nameserver < ActiveRecord::Base delegate :name, to: :domain, prefix: true + self.ignored_columns = %w[legacy_domain_id] + def epp_code_map { '2302' => [ @@ -46,7 +48,7 @@ class Nameserver < ActiveRecord::Base [:ipv6, :invalid, { value: { obj: 'hostAddr', val: ipv6 } }] ], '2003' => [ - [:ipv4, :blank] + %i[base ip_required], ] } end @@ -81,11 +83,12 @@ class Nameserver < ActiveRecord::Base def glue_record_required? return unless hostname? && domain + DomainName(hostname).domain == domain.name end def normalize_attributes - self.hostname = hostname.try(:strip).try(:downcase) + self.hostname = hostname.try(:strip).try(:downcase).gsub(/\.$/, '') self.ipv4 = Array(ipv4).reject(&:blank?).map(&:strip) self.ipv6 = Array(ipv6).reject(&:blank?).map(&:strip).map(&:upcase) end diff --git a/app/models/notification.rb b/app/models/notification.rb index d6427323b..e83b2c9da 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,4 +1,4 @@ -class Notification < ActiveRecord::Base +class Notification < ApplicationRecord include Versions # version/notification_version.rb belongs_to :registrar diff --git a/app/models/payment_order.rb b/app/models/payment_order.rb new file mode 100644 index 000000000..4317abb38 --- /dev/null +++ b/app/models/payment_order.rb @@ -0,0 +1,102 @@ +class PaymentOrder < ApplicationRecord + include Versions + include ActionView::Helpers::NumberHelper + + PAYMENT_INTERMEDIARIES = ENV['payments_intermediaries'].to_s.strip.split(', ').freeze + PAYMENT_BANKLINK_BANKS = ENV['payments_banks'].to_s.strip.split(', ').freeze + INTERNAL_PAYMENT_METHODS = %w[admin_payment system_payment].freeze + PAYMENT_METHODS = [PAYMENT_INTERMEDIARIES, PAYMENT_BANKLINK_BANKS, + INTERNAL_PAYMENT_METHODS].flatten.freeze + CUSTOMER_PAYMENT_METHODS = [PAYMENT_INTERMEDIARIES, PAYMENT_BANKLINK_BANKS].flatten.freeze + + belongs_to :invoice, optional: false + + validate :invoice_cannot_be_already_paid, on: :create + validate :supported_payment_method + + enum status: { issued: 'issued', paid: 'paid', cancelled: 'cancelled', + failed: 'failed' } + + attr_accessor :return_url, :response_url + + def self.supported_methods + supported = [] + + PAYMENT_METHODS.each do |method| + class_name = ('PaymentOrders::' + method.camelize).constantize + raise(NoMethodError, class_name) unless class_name < PaymentOrder + + supported << class_name + end + + supported + end + + def self.new_with_type(type:, invoice:) + channel = ('PaymentOrders::' + type.camelize).constantize + + PaymentOrder.new(type: channel, invoice: invoice) + end + + # Name of configuration namespace + def self.config_namespace_name; end + + def supported_payment_method + return if PaymentOrder.supported_method?(type) + + errors.add(:type, 'is not supported') + end + + def invoice_cannot_be_already_paid + return unless invoice&.paid? + + errors.add(:invoice, 'is already paid') + end + + def self.supported_method?(name, shortname: false) + some_class = if shortname + ('PaymentOrders::' + name.camelize).constantize + else + name.constantize + end + supported_methods.include? some_class + rescue NameError + false + end + + def base_transaction(sum:, paid_at:, buyer_name:) + BankTransaction.new( + description: invoice.order, + reference_no: invoice.reference_no, + currency: invoice.currency, + iban: invoice.seller_iban, + sum: sum, + paid_at: paid_at, + buyer_name: buyer_name + ) + end + + def complete_transaction + return NoMethodError unless payment_received? + + paid! + transaction = composed_transaction + transaction.save! && transaction.bind_invoice(invoice.number) + return unless transaction.errors.any? + + worded_errors = 'Failed to bind. ' + transaction.errors.full_messages.each do |err| + worded_errors << "#{err}, " + end + + update!(notes: worded_errors) + end + + def channel + type.gsub('PaymentOrders::', '') + end + + def form_url + ENV["payments_#{self.class.config_namespace_name}_url"] + end +end diff --git a/app/models/payment_orders.rb b/app/models/payment_orders.rb deleted file mode 100644 index 921af0cd4..000000000 --- a/app/models/payment_orders.rb +++ /dev/null @@ -1,15 +0,0 @@ -module PaymentOrders - PAYMENT_INTERMEDIARIES = ENV['payments_intermediaries'].to_s.strip.split(', ').freeze - PAYMENT_BANKLINK_BANKS = ENV['payments_banks'].to_s.strip.split(', ').freeze - PAYMENT_METHODS = [PAYMENT_INTERMEDIARIES, PAYMENT_BANKLINK_BANKS].flatten.freeze - - def self.create_with_type(type, invoice, opts = {}) - raise ArgumentError unless PAYMENT_METHODS.include?(type) - - if PAYMENT_BANKLINK_BANKS.include?(type) - BankLink.new(type, invoice, opts) - elsif type == 'every_pay' - EveryPay.new(type, invoice, opts) - end - end -end diff --git a/app/models/payment_orders/admin_payment.rb b/app/models/payment_orders/admin_payment.rb new file mode 100644 index 000000000..05ae061fb --- /dev/null +++ b/app/models/payment_orders/admin_payment.rb @@ -0,0 +1,9 @@ +module PaymentOrders + class AdminPayment < PaymentOrder + CONFIG_NAMESPACE = 'admin_payment'.freeze + + def self.config_namespace_name + CONFIG_NAMESPACE + end + end +end diff --git a/app/models/payment_orders/bank_link.rb b/app/models/payment_orders/bank_link.rb index e568da0df..c8714d245 100644 --- a/app/models/payment_orders/bank_link.rb +++ b/app/models/payment_orders/bank_link.rb @@ -1,44 +1,44 @@ module PaymentOrders - class BankLink < Base - BANK_LINK_VERSION = '008' + class BankLink < PaymentOrder + BANK_LINK_VERSION = '008'.freeze - NEW_TRANSACTION_SERVICE_NUMBER = '1012' - SUCCESSFUL_PAYMENT_SERVICE_NUMBER = '1111' - CANCELLED_PAYMENT_SERVICE_NUMBER = '1911' + NEW_TRANSACTION_SERVICE_NUMBER = '1012'.freeze + SUCCESSFUL_PAYMENT_SERVICE_NUMBER = '1111'.freeze + CANCELLED_PAYMENT_SERVICE_NUMBER = '1911'.freeze - NEW_MESSAGE_KEYS = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_STAMP VK_AMOUNT + NEW_MESSAGE_KEYS = %w[VK_SERVICE VK_VERSION VK_SND_ID VK_STAMP VK_AMOUNT VK_CURR VK_REF VK_MSG VK_RETURN VK_CANCEL - VK_DATETIME).freeze - SUCCESS_MESSAGE_KEYS = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP + VK_DATETIME].freeze + SUCCESS_MESSAGE_KEYS = %w[VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP VK_T_NO VK_AMOUNT VK_CURR VK_REC_ACC VK_REC_NAME VK_SND_ACC VK_SND_NAME VK_REF VK_MSG - VK_T_DATETIME).freeze - CANCEL_MESSAGE_KEYS = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP - VK_REF VK_MSG).freeze + VK_T_DATETIME].freeze + CANCEL_MESSAGE_KEYS = %w[VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP + VK_REF VK_MSG].freeze def form_fields hash = {} - hash["VK_SERVICE"] = NEW_TRANSACTION_SERVICE_NUMBER - hash["VK_VERSION"] = BANK_LINK_VERSION - hash["VK_SND_ID"] = seller_account - hash["VK_STAMP"] = invoice.number - hash["VK_AMOUNT"] = number_with_precision(invoice.total, precision: 2, separator: ".") - hash["VK_CURR"] = invoice.currency - hash["VK_REF"] = "" - hash["VK_MSG"] = invoice.order - hash["VK_RETURN"] = return_url - hash["VK_CANCEL"] = return_url - hash["VK_DATETIME"] = Time.zone.now.strftime("%Y-%m-%dT%H:%M:%S%z") - hash["VK_MAC"] = calc_mac(hash) - hash["VK_ENCODING"] = "UTF-8" - hash["VK_LANG"] = "ENG" + hash['VK_SERVICE'] = NEW_TRANSACTION_SERVICE_NUMBER + hash['VK_VERSION'] = BANK_LINK_VERSION + hash['VK_SND_ID'] = seller_account + hash['VK_STAMP'] = invoice.number + hash['VK_AMOUNT'] = number_with_precision(invoice.total, precision: 2, separator: ".") + hash['VK_CURR'] = invoice.currency + hash['VK_REF'] = '' + hash['VK_MSG'] = invoice.order + hash['VK_RETURN'] = return_url + hash['VK_CANCEL'] = return_url + hash['VK_DATETIME'] = Time.zone.now.strftime('%Y-%m-%dT%H:%M:%S%z') + hash['VK_MAC'] = calc_mac(hash) + hash['VK_ENCODING'] = 'UTF-8' + hash['VK_LANG'] = 'ENG' hash end def valid_response_from_intermediary? return false unless response - case response["VK_SERVICE"] + case response['VK_SERVICE'] when SUCCESSFUL_PAYMENT_SERVICE_NUMBER valid_successful_transaction? when CANCELLED_PAYMENT_SERVICE_NUMBER @@ -48,28 +48,31 @@ module PaymentOrders end end - def complete_transaction - return unless valid_successful_transaction? + def payment_received? + valid_response_from_intermediary? && settled_payment? + end - transaction = BankTransaction.find_by( - description: invoice.order, - currency: invoice.currency, - iban: invoice.seller_iban - ) + def create_failure_report + notes = "User failed to make payment. Bank responded with code #{response['VK_SERVICE']}" + status = 'cancelled' + update!(notes: notes, status: status) + end - transaction.sum = response['VK_AMOUNT'] - transaction.bank_reference = response['VK_T_NO'] - transaction.buyer_bank_code = response["VK_SND_ID"] - transaction.buyer_iban = response["VK_SND_ACC"] - transaction.buyer_name = response["VK_SND_NAME"] - transaction.paid_at = Time.parse(response["VK_T_DATETIME"]) + def composed_transaction + paid_at = Time.parse(response['VK_T_DATETIME']) + transaction = base_transaction(sum: response['VK_AMOUNT'], + paid_at: paid_at, + buyer_name: response['VK_SND_NAME']) - transaction.save! - transaction.autobind_invoice + transaction.bank_reference = response['VK_T_NO'] + transaction.buyer_bank_code = response['VK_SND_ID'] + transaction.buyer_iban = response['VK_SND_ACC'] + + transaction end def settled_payment? - response["VK_SERVICE"] == SUCCESSFUL_PAYMENT_SERVICE_NUMBER + response['VK_SERVICE'] == SUCCESSFUL_PAYMENT_SERVICE_NUMBER end private @@ -88,17 +91,15 @@ module PaymentOrders def valid_amount? source = number_with_precision( - BigDecimal.new(response["VK_AMOUNT"]), precision: 2, separator: "." - ) - target = number_with_precision( - invoice.total, precision: 2, separator: "." + BigDecimal(response['VK_AMOUNT']), precision: 2, separator: '.' ) + target = number_with_precision(invoice.total, precision: 2, separator: '.') source == target end def valid_currency? - invoice.currency == response["VK_CURR"] + invoice.currency == response['VK_CURR'] end def sign(data) @@ -116,7 +117,7 @@ module PaymentOrders def valid_mac?(hash, keys) data = keys.map { |element| prepend_size(hash[element]) }.join - verify_mac(data, hash["VK_MAC"]) + verify_mac(data, hash['VK_MAC']) end def verify_mac(data, mac) @@ -125,22 +126,22 @@ module PaymentOrders end def prepend_size(value) - value = (value || "").to_s.strip - string = "" + value = (value || '').to_s.strip + string = '' string << format("%03i", value.size) string << value end def seller_account - ENV["payments_#{type}_seller_account"] + ENV["payments_#{self.class.config_namespace_name}_seller_account"] end def seller_certificate - ENV["payments_#{type}_seller_private"] + ENV["payments_#{self.class.config_namespace_name}_seller_private"] end def bank_certificate - ENV["payments_#{type}_bank_certificate"] + ENV["payments_#{self.class.config_namespace_name}_bank_certificate"] end end end diff --git a/app/models/payment_orders/base.rb b/app/models/payment_orders/base.rb deleted file mode 100644 index cf0293025..000000000 --- a/app/models/payment_orders/base.rb +++ /dev/null @@ -1,33 +0,0 @@ -module PaymentOrders - class Base - include ActionView::Helpers::NumberHelper - - attr_reader :type, - :invoice, - :return_url, - :response_url, - :response - - def initialize(type, invoice, opts = {}) - @type = type - @invoice = invoice - @return_url = opts[:return_url] - @response_url = opts[:response_url] - @response = opts[:response] - end - - def create_transaction - transaction = BankTransaction.where(description: invoice.order).first_or_initialize( - reference_no: invoice.reference_no, - currency: invoice.currency, - iban: invoice.seller_iban - ) - - transaction.save! - end - - def form_url - ENV["payments_#{type}_url"] - end - end -end diff --git a/app/models/payment_orders/every_pay.rb b/app/models/payment_orders/every_pay.rb index b4ddcdf29..2695c20e0 100644 --- a/app/models/payment_orders/every_pay.rb +++ b/app/models/payment_orders/every_pay.rb @@ -1,9 +1,15 @@ module PaymentOrders - class EveryPay < Base - USER = ENV['payments_every_pay_api_user'].freeze - KEY = ENV['payments_every_pay_api_key'].freeze - ACCOUNT_ID = ENV['payments_every_pay_seller_account'].freeze - SUCCESSFUL_PAYMENT = %w(settled authorized).freeze + class EveryPay < PaymentOrder + USER = ENV['payments_every_pay_api_user'] + KEY = ENV['payments_every_pay_api_key'] + ACCOUNT_ID = ENV['payments_every_pay_seller_account'] + SUCCESSFUL_PAYMENT = %w[settled authorized].freeze + + CONFIG_NAMESPACE = 'every_pay'.freeze + + def self.config_namespace_name + CONFIG_NAMESPACE + end def form_fields base_json = base_params @@ -20,28 +26,28 @@ module PaymentOrders def valid_response_from_intermediary? return false unless response + valid_hmac? && valid_amount? && valid_account? end def settled_payment? - SUCCESSFUL_PAYMENT.include?(response[:payment_state]) + SUCCESSFUL_PAYMENT.include?(response['payment_state']) end - def complete_transaction - return unless valid_response_from_intermediary? && settled_payment? + def payment_received? + valid_response_from_intermediary? && settled_payment? + end - transaction = BankTransaction.find_by( - description: invoice.order, - currency: invoice.currency, - iban: invoice.seller_iban - ) + def composed_transaction + base_transaction(sum: response['amount'], + paid_at: Date.strptime(response['timestamp'], '%s'), + buyer_name: response['cc_holder_name']) + end - transaction.sum = response[:amount] - transaction.paid_at = Date.strptime(response[:timestamp], '%s') - transaction.buyer_name = response[:cc_holder_name] - - transaction.save! - transaction.autobind_invoice + def create_failure_report + notes = "User failed to make valid payment. Payment state: #{response['payment_state']}" + status = 'cancelled' + update!(notes: notes, status: status) end private @@ -61,24 +67,27 @@ module PaymentOrders end def valid_hmac? - hmac_fields = response[:hmac_fields].split(',') + hmac_fields = response['hmac_fields'].split(',') hmac_hash = {} hmac_fields.map do |field| - symbol = field.to_sym - hmac_hash[symbol] = response[symbol] + hmac_hash[field] = response[field] end hmac_string = hmac_hash.map { |key, _v| "#{key}=#{hmac_hash[key]}" }.join('&') expected_hmac = OpenSSL::HMAC.hexdigest('sha1', KEY, hmac_string) - expected_hmac == response[:hmac] + expected_hmac == response['hmac'] + rescue NoMethodError + false end def valid_amount? - invoice.total == BigDecimal.new(response[:amount]) + return false unless response.key? 'amount' + + invoice.total == BigDecimal(response['amount']) end def valid_account? - response[:account_id] == ACCOUNT_ID + response['account_id'] == ACCOUNT_ID end end end diff --git a/app/models/payment_orders/lhv.rb b/app/models/payment_orders/lhv.rb new file mode 100644 index 000000000..4c9f59c4a --- /dev/null +++ b/app/models/payment_orders/lhv.rb @@ -0,0 +1,7 @@ +module PaymentOrders + class Lhv < BankLink + def self.config_namespace_name + 'lhv' + end + end +end diff --git a/app/models/payment_orders/seb.rb b/app/models/payment_orders/seb.rb new file mode 100644 index 000000000..878d877a7 --- /dev/null +++ b/app/models/payment_orders/seb.rb @@ -0,0 +1,7 @@ +module PaymentOrders + class Seb < BankLink + def self.config_namespace_name + 'seb' + end + end +end diff --git a/app/models/payment_orders/swed.rb b/app/models/payment_orders/swed.rb new file mode 100644 index 000000000..ff3aca3d1 --- /dev/null +++ b/app/models/payment_orders/swed.rb @@ -0,0 +1,7 @@ +module PaymentOrders + class Swed < BankLink + def self.config_namespace_name + 'swed' + end + end +end diff --git a/app/models/payment_orders/system_payment.rb b/app/models/payment_orders/system_payment.rb new file mode 100644 index 000000000..47c75ebe3 --- /dev/null +++ b/app/models/payment_orders/system_payment.rb @@ -0,0 +1,9 @@ +module PaymentOrders + class SystemPayment < PaymentOrder + CONFIG_NAMESPACE = 'system_payment'.freeze + + def self.config_namespace_name + CONFIG_NAMESPACE + end + end +end diff --git a/app/models/que_job.rb b/app/models/que_job.rb index 5eed581fc..f9dd50ac8 100644 --- a/app/models/que_job.rb +++ b/app/models/que_job.rb @@ -1,4 +1,4 @@ # To be able to remove existing jobs -class QueJob < ActiveRecord::Base +class QueJob < ApplicationRecord self.primary_key = 'job_id' end diff --git a/app/models/registrant_user.rb b/app/models/registrant_user.rb index 1e787b8b3..e7ce9cc3b 100644 --- a/app/models/registrant_user.rb +++ b/app/models/registrant_user.rb @@ -98,4 +98,4 @@ class RegistrantUser < User user end end -end \ No newline at end of file +end diff --git a/app/models/registrant_verification.rb b/app/models/registrant_verification.rb index 95e24d36b..097f0cfa9 100644 --- a/app/models/registrant_verification.rb +++ b/app/models/registrant_verification.rb @@ -1,17 +1,19 @@ # Used in Registrant portal to collect registrant verifications # Registrant postgres user can access this table directly. -class RegistrantVerification < ActiveRecord::Base +class RegistrantVerification < ApplicationRecord + include Versions # version/domain_version.rb + # actions CONFIRMED = 'confirmed' REJECTED = 'rejected' - + # action types DOMAIN_REGISTRANT_CHANGE = 'domain_registrant_change' DOMAIN_DELETE = 'domain_delete' belongs_to :domain - validates :verification_token, :domain_name, :domain, :action, :action_type, presence: true + validates :verification_token, :domain, :action, :action_type, presence: true def domain_registrant_change_confirm!(initiator) self.action_type = DOMAIN_REGISTRANT_CHANGE diff --git a/app/models/registrar.rb b/app/models/registrar.rb index fa8747114..470d768b7 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -1,5 +1,8 @@ -class Registrar < ActiveRecord::Base +class Registrar < ApplicationRecord include Versions # version/registrar_version.rb + include Concerns::Registrar::BookKeeping + include Concerns::EmailVerifable + include Concerns::Registrar::LegalDoc has_many :domains, dependent: :restrict_with_error has_many :contacts, dependent: :restrict_with_error @@ -21,20 +24,17 @@ class Registrar < ActiveRecord::Base validates :reference_no, format: Billing::ReferenceNo::REGEXP validate :forbid_special_code - validates :vat_rate, presence: true, if: 'vat_liable_in_foreign_country? && vat_no.blank?' + validates :vat_rate, presence: true, if: -> { vat_liable_in_foreign_country? && vat_no.blank? } validates :vat_rate, absence: true, if: :vat_liable_locally? - validates :vat_rate, absence: true, if: 'vat_liable_in_foreign_country? && vat_no?' + validates :vat_rate, absence: true, if: -> { vat_liable_in_foreign_country? && vat_no? } validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 }, allow_nil: true - validate :forbid_special_code - attribute :vat_rate, ::Type::VATRate.new after_initialize :set_defaults - validates :email, email_format: { message: :invalid }, - allow_blank: true, if: proc { |c| c.email_changed? } - validates :billing_email, email_format: { message: :invalid }, allow_blank: true + validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? } + validate :correct_billing_email_format alias_attribute :contact_email, :email @@ -46,6 +46,8 @@ class Registrar < ActiveRecord::Base RegenerateRegistrarWhoisesJob.enqueue id end + self.ignored_columns = %w[legacy_id] + class << self def ordered order(name: :asc) @@ -97,9 +99,7 @@ class Registrar < ActiveRecord::Base } ] ) - - e_invoice = invoice.to_e_invoice - e_invoice.deliver + SendEInvoiceJob.enqueue(invoice.id) invoice end @@ -194,4 +194,4 @@ class Registrar < ActiveRecord::Base def vat_liable_in_foreign_country? !vat_liable_locally? end -end \ No newline at end of file +end diff --git a/app/models/reserved_domain.rb b/app/models/reserved_domain.rb index 2e3d17a20..4c9df3269 100644 --- a/app/models/reserved_domain.rb +++ b/app/models/reserved_domain.rb @@ -1,13 +1,17 @@ -class ReservedDomain < ActiveRecord::Base +class ReservedDomain < ApplicationRecord include Versions # version/reserved_domain_version.rb + include WhoisStatusPopulate before_save :fill_empty_passwords before_save :generate_data + before_save :sync_dispute_password after_destroy :remove_data validates :name, domain_name: true, uniqueness: true alias_attribute :registration_code, :password + self.ignored_columns = %w[legacy_id] + class << self def pw_for(domain_name) name_in_ascii = SimpleIDN.to_ascii(domain_name) @@ -39,23 +43,21 @@ class ReservedDomain < ActiveRecord::Base self.password = SecureRandom.hex end + def sync_dispute_password + dispute = Dispute.active.find_by(domain_name: name) + self.password = dispute.password if dispute.present? + end + def generate_data return if Domain.where(name: name).any? wr = Whois::Record.find_or_initialize_by(name: name) - wr.json = @json = generate_json # we need @json to bind to class + wr.json = @json = generate_json(wr, domain_status: 'Reserved') # we need @json to bind to class wr.save end alias_method :update_whois_record, :generate_data - def generate_json - h = HashWithIndifferentAccess.new - h[:name] = self.name - h[:status] = ['Reserved'] - h - end - def remove_data UpdateWhoisRecordJob.enqueue name, 'reserved' end diff --git a/app/models/retained_domains.rb b/app/models/retained_domains.rb new file mode 100644 index 000000000..d9ab42b3b --- /dev/null +++ b/app/models/retained_domains.rb @@ -0,0 +1,91 @@ +# Hiding the queries behind its own class will allow us to include disputed or +# auctioned domains without meddling up with controller logic. +class RetainedDomains + RESERVED = 'reserved'.freeze + BLOCKED = 'blocked'.freeze + DISPUTED = 'disputed'.freeze + + attr_reader :domains, + :type + + def initialize(params) + @type = establish_type(params) + @domains = gather_domains + end + + delegate :count, to: :domains + + def to_jsonable + domains.map { |el| domain_to_jsonable(el) } + end + + private + + def establish_type(params) + type = params[:type] + + case type + when RESERVED then :reserved + when BLOCKED then :blocked + when DISPUTED then :disputed + else :all + end + end + + def gather_domains + blocked_domains.to_a + .union(reserved_domains.to_a) + .union(disputed_domains.to_a) + end + + def blocked_domains + if %i[all blocked].include?(type) + BlockedDomain.order(name: :desc).all + else + [] + end + end + + def reserved_domains + if %i[all reserved].include?(type) + ReservedDomain.order(name: :desc).all + else + [] + end + end + + def disputed_domains + if %i[all disputed].include?(type) + Dispute.order(domain_name: :desc).active + else + [] + end + end + + def domain_to_jsonable(domain) + status = get_status(domain) + domain_name = get_domain_name(domain) + punycode = SimpleIDN.to_ascii(domain_name) + + { + name: domain_name, + status: status, + punycode_name: punycode, + } + end + + def get_status(domain) + case domain + when ReservedDomain then RESERVED + when BlockedDomain then BLOCKED + when Dispute then DISPUTED + end + end + + def get_domain_name(domain) + case domain + when Dispute then domain.domain_name + else domain.name + end + end +end diff --git a/app/models/setting.rb b/app/models/setting.rb index 64a20c34f..86d3dff35 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -3,7 +3,7 @@ class Setting < RailsSettings::Base source Rails.root.join('config', 'app.yml') # When config/app.yml has changed, you need change this prefix to v2, v3 ... to expires caches - # cache_prefix { "v1" } + cache_prefix { 'v2' } def self.reload_settings! STDOUT << "#{Time.zone.now.utc} - Clearing settings cache\n" @@ -46,6 +46,7 @@ class Setting < RailsSettings::Base expire_warning_period redemption_grace_period expire_pending_confirmation + dispute_period_in_months ] end @@ -67,6 +68,7 @@ class Setting < RailsSettings::Base request_confirmation_on_domain_deletion_enabled nameserver_required address_processing + legal_document_is_mandatory ] end end diff --git a/app/models/type/vat_rate.rb b/app/models/type/vat_rate.rb index 5ee993211..6a31e389b 100644 --- a/app/models/type/vat_rate.rb +++ b/app/models/type/vat_rate.rb @@ -1,10 +1,10 @@ module Type class VATRate < ActiveRecord::Type::Decimal - def type_cast_from_database(value) + def deserialize(value) super * 100 if value end - def type_cast_for_database(value) + def serialize(value) super / 100.0 if value end end diff --git a/app/models/user.rb b/app/models/user.rb index 573cddc94..6b16bd508 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,10 +1,12 @@ -class User < ActiveRecord::Base +class User < ApplicationRecord include Versions # version/user_version.rb has_many :actions, dependent: :restrict_with_exception attr_accessor :phone + self.ignored_columns = %w[legacy_id] + def id_role_username "#{self.id}-#{self.class}: #{self.username}" end diff --git a/app/models/version/payment_order_version.rb b/app/models/version/payment_order_version.rb new file mode 100644 index 000000000..e556f1021 --- /dev/null +++ b/app/models/version/payment_order_version.rb @@ -0,0 +1,4 @@ +class PaymentOrderVersion < PaperTrail::Version + self.table_name = :log_payment_orders + self.sequence_name = :log_payment_orders_id_seq +end diff --git a/app/models/version/registrant_verification_version.rb b/app/models/version/registrant_verification_version.rb new file mode 100644 index 000000000..b7dbb8852 --- /dev/null +++ b/app/models/version/registrant_verification_version.rb @@ -0,0 +1,7 @@ +class RegistrantVerificationVersion < PaperTrail::Version + include VersionSession + self.table_name = :log_registrant_verifications + self.sequence_name = :log_registrant_verifications_id_seq + + scope :deleted, -> { where(event: 'destroy') } +end diff --git a/app/models/white_ip.rb b/app/models/white_ip.rb index 251fc60ac..303ff5886 100644 --- a/app/models/white_ip.rb +++ b/app/models/white_ip.rb @@ -1,4 +1,4 @@ -class WhiteIp < ActiveRecord::Base +class WhiteIp < ApplicationRecord include Versions belongs_to :registrar diff --git a/app/models/whois/record.rb b/app/models/whois/record.rb index ae7422403..1d827e22a 100644 --- a/app/models/whois/record.rb +++ b/app/models/whois/record.rb @@ -16,7 +16,8 @@ module Whois elsif auction.awaiting_payment? || auction.payment_received? update!(json: { name: auction.domain, status: ['PendingRegistration'], - disclaimer: self.class.disclaimer }) + disclaimer: self.class.disclaimer, + registration_deadline: auction.whois_deadline }) end end end diff --git a/app/models/whois/server.rb b/app/models/whois/server.rb index 2cec52e4e..bec234b6b 100644 --- a/app/models/whois/server.rb +++ b/app/models/whois/server.rb @@ -1,5 +1,5 @@ module Whois - class Server < ActiveRecord::Base + class Server < ApplicationRecord self.abstract_class = true establish_connection :"whois_#{Rails.env}" end diff --git a/app/models/whois_record.rb b/app/models/whois_record.rb index 8d91c85ee..4994283c9 100644 --- a/app/models/whois_record.rb +++ b/app/models/whois_record.rb @@ -1,5 +1,5 @@ require "erb" -class WhoisRecord < ActiveRecord::Base +class WhoisRecord < ApplicationRecord belongs_to :domain belongs_to :registrar @@ -84,6 +84,7 @@ class WhoisRecord < ActiveRecord::Base def populate return if domain_id.blank? + self.json = generated_json self.name = json['name'] self.registrar_id = domain.registrar_id if domain # for faster registrar updates diff --git a/app/validators/domain_name_validator.rb b/app/validators/domain_name_validator.rb index 0d5638b37..3372bb952 100644 --- a/app/validators/domain_name_validator.rb +++ b/app/validators/domain_name_validator.rb @@ -1,4 +1,6 @@ class DomainNameValidator < ActiveModel::EachValidator + # rubocop:disable Metrics/CyclomaticComplexity + # rubocop:disable Metrics/LineLength def validate_each(record, attribute, value) if !self.class.validate_format(value) record.errors[attribute] << (options[:message] || record.errors.generate_message(attribute, :invalid)) @@ -27,14 +29,19 @@ class DomainNameValidator < ActiveModel::EachValidator end unicode_chars = /\u00E4\u00F5\u00F6\u00FC\u0161\u017E/ # äõöüšž - regexp = /\A[a-zA-Z0-9#{unicode_chars.source}][a-zA-Z0-9#{unicode_chars.source}-]{0,61}[a-zA-Z0-9#{unicode_chars.source}]\.#{general_domains.source}\z/ - !!(value =~ regexp) + regexp = /\A[a-zA-Z0-9#{unicode_chars.source}][a-zA-Z0-9#{unicode_chars.source}-]{0,62}\.#{general_domains.source}\z/ + end_regexp = /\-\.#{general_domains.source}\z/ # should not contain dash as a closing char + !!(value =~ regexp && value !~ end_regexp) end def validate_blocked(value) return true unless value - return false if BlockedDomain.where(name: value).count.positive? + return false if BlockedDomain.where(name: value).any? + return false if BlockedDomain.where(name: SimpleIDN.to_unicode(value)).any? + DNS::Zone.where(origin: value).count.zero? end end + # rubocop:enable Metrics/CyclomaticComplexity + # rubocop:enable Metrics/LineLength end diff --git a/app/views/admin/api_users/_api_user.html.erb b/app/views/admin/api_users/_api_user.html.erb new file mode 100644 index 000000000..d8412a519 --- /dev/null +++ b/app/views/admin/api_users/_api_user.html.erb @@ -0,0 +1,5 @@ + + <%= link_to api_user, admin_registrar_api_user_path(api_user.registrar, api_user) %> + <%= link_to api_user.registrar, admin_registrar_path(api_user.registrar) %> + <%= api_user.active %> + diff --git a/app/views/admin/api_users/_form.haml b/app/views/admin/api_users/_form.haml deleted file mode 100644 index 12ea322aa..000000000 --- a/app/views/admin/api_users/_form.haml +++ /dev/null @@ -1,57 +0,0 @@ -= form_for([:admin, @api_user], multipart: true, - html: {class: 'form-horizontal', autocomplete: 'off'}) do |f| - = render 'shared/full_errors', object: @api_user - - .row - .col-md-8 - .form-group - .col-md-4.control-label - = f.label :username, nil, class: 'required' - .col-md-7 - = f.text_field :username, required: true, autofocus: true, class: 'form-control' - .form-group - .col-md-4.control-label - = f.label :plain_text_password, nil, class: 'required' - .col-md-7 - = f.text_field :plain_text_password, required: true, class: 'form-control' - - .form-group - .col-md-4.control-label - = f.label :identity_code - .col-md-7 - = f.text_field(:identity_code, class: 'form-control') - - .form-group - .form-group.has-feedback.js-typeahead-container - .col-md-4.control-label - = f.label :registrar_typeahead, t(:registrar_name), class: 'required' - .col-md-7 - = f.text_field(:registrar_typeahead, - class: 'form-control js-registrar-typeahead typeahead required', - placeholder: t(:registrar_name), autocomplete: 'off') - %span.glyphicon.glyphicon-ok.form-control-feedback.js-typeahead-ok.hidden - %span.glyphicon.glyphicon-remove.form-control-feedback.js-typeahead-remove - = f.hidden_field(:registrar_id, class: 'js-registrar-id') - - .form-group - .col-md-4.control-label - = f.label :role, nil, class: 'required' - .col-md-7 - = select_tag 'api_user[roles][]', - options_for_select(ApiUser::ROLES.map {|x| [x, x] }, @api_user.roles.try(:first)), - class: 'form-control selectize' - .checkbox - %label{for: 'api_user_active'} - = f.check_box(:active) - = t('.active') - - %hr - - .row - .col-md-8.text-right - = button_tag(t(:save), class: 'btn btn-primary') - -:javascript - window.addEventListener('load', function() { - Autocomplete.bindAdminRegistrarSearch(); - }); diff --git a/app/views/admin/api_users/_form.html.erb b/app/views/admin/api_users/_form.html.erb new file mode 100644 index 000000000..ad6ee6b2b --- /dev/null +++ b/app/views/admin/api_users/_form.html.erb @@ -0,0 +1,58 @@ +<%= form_for([:admin, @api_user.registrar, @api_user], html: { class: 'form-horizontal', autocomplete: 'off' }) do |f| %> + <%= render 'form_errors', target: @api_user %> + +
+
+
+
+ <%= f.label :username, nil, class: 'required' %> +
+
+ <%= f.text_field :username, required: true, autofocus: true, class: 'form-control' %> +
+
+ +
+
+ <%= f.label :plain_text_password, nil, class: 'required' %> +
+
+ <%= f.text_field :plain_text_password, required: true, class: 'form-control' %> +
+
+ +
+
+ <%= f.label :identity_code %> +
+
+ <%= f.text_field(:identity_code, class: 'form-control') %> +
+
+ +
+
+ <%= f.label :roles, nil, for: nil, class: 'required' %> +
+ +
+ <%= select_tag 'api_user[roles][]', options_for_select(ApiUser::ROLES.map { |x| [x, x] }, @api_user.roles.try(:first)), class: 'form-control selectize' %> +
+ +
+
+
+
+
+ +
+ +
+
+ <%= button_tag t(".#{f.object.new_record? ? 'create' : 'update'}_btn"), class: 'btn btn-success' %> +
+
+<% end %> diff --git a/app/views/admin/api_users/edit.haml b/app/views/admin/api_users/edit.haml deleted file mode 100644 index 867d084d5..000000000 --- a/app/views/admin/api_users/edit.haml +++ /dev/null @@ -1,5 +0,0 @@ -- content_for :actions do - = link_to(t(:back_to_api_user), [:admin, @api_user], class: 'btn btn-default') -= render 'shared/title', name: "#{t(:edit)}: #{@api_user.username}" - -= render 'form' diff --git a/app/views/admin/api_users/edit.html.erb b/app/views/admin/api_users/edit.html.erb new file mode 100644 index 000000000..d065c885c --- /dev/null +++ b/app/views/admin/api_users/edit.html.erb @@ -0,0 +1,14 @@ + + + + +<%= render 'form' %> diff --git a/app/views/admin/api_users/index.haml b/app/views/admin/api_users/index.haml deleted file mode 100644 index 4815607a7..000000000 --- a/app/views/admin/api_users/index.haml +++ /dev/null @@ -1,25 +0,0 @@ -- content_for :actions do - = link_to(t('.new_btn'), new_admin_api_user_path, class: 'btn btn-primary') -= render 'shared/title', name: t('.title') - -.row - .col-md-12 - .table-responsive - %table.table.table-hover.table-bordered.table-condensed - %thead - %tr - %th{class: 'col-xs-2'} - = sort_link(@q, 'username') - %th{class: 'col-xs-2'} - = sort_link(@q, 'registrar_name', t(:registrar_name)) - %th{class: 'col-xs-2'} - = sort_link(@q, 'active', t('.active')) - %tbody - - @api_users.each do |x| - %tr - %td= link_to(x, [:admin, x]) - %td= link_to(x.registrar, [:admin, x.registrar]) - %td= x.active -.row - .col-md-12 - = paginate @api_users diff --git a/app/views/admin/api_users/index.html.erb b/app/views/admin/api_users/index.html.erb new file mode 100644 index 000000000..9c00f32d6 --- /dev/null +++ b/app/views/admin/api_users/index.html.erb @@ -0,0 +1,35 @@ + + +
+
+
+ + + + + + + + + + + <%= render @api_users %> + +
+ <%= sort_link(@q, 'username') %> + + <%= sort_link(@q, 'registrar_name', Registrar.model_name.human) %> + + <%= sort_link(@q, 'active', ApiUser.human_attribute_name(:active)) %> +
+
+
+
+ +
+
+ <%= paginate @api_users %> +
+
diff --git a/app/views/admin/api_users/new.haml b/app/views/admin/api_users/new.haml deleted file mode 100644 index f8282f44f..000000000 --- a/app/views/admin/api_users/new.haml +++ /dev/null @@ -1,3 +0,0 @@ -= render 'shared/title', name: t('.title') - -= render 'form' diff --git a/app/views/admin/api_users/new.html.erb b/app/views/admin/api_users/new.html.erb new file mode 100644 index 000000000..b3f4580e1 --- /dev/null +++ b/app/views/admin/api_users/new.html.erb @@ -0,0 +1,11 @@ + + + + +<%= render 'form' %> diff --git a/app/views/admin/api_users/show.haml b/app/views/admin/api_users/show.haml deleted file mode 100644 index 2e13445d1..000000000 --- a/app/views/admin/api_users/show.haml +++ /dev/null @@ -1,61 +0,0 @@ -- content_for :actions do - = link_to(t(:edit), edit_admin_api_user_path(@api_user), class: 'btn btn-default') - = link_to(t(:delete), admin_api_user_path(@api_user), - method: :delete, data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger') -= render 'shared/title', name: @api_user.username - -- if @api_user.errors.any? - - @api_user.errors.each do |attr, err| - = err - %br -- if @api_user.errors.any? - %hr -.row - .col-md-12 - .panel.panel-default - .panel-heading - %h3.panel-title= t(:general) - .panel-body - %dl.dl-horizontal - %dt= t(:username) - %dd= @api_user.username - - %dt= t(:password) - %dd= @api_user.plain_text_password - - %dt= t(:registrar_name) - %dd= link_to(@api_user.registrar, admin_registrar_path(@api_user.registrar)) - - %dt= t(:role) - %dd= @api_user.roles.join(', ') - - %dt= t('.active') - %dd= @api_user.active -.row - .col-md-12 - .panel.panel-default - .panel-heading.clearfix - .pull-left - = t(:certificates) - .pull-right - = link_to(t(:upload_crt), - new_admin_api_user_certificate_path(@api_user, crt: true), class: 'btn btn-primary btn-xs') - = link_to(t(:upload_csr), - new_admin_api_user_certificate_path(@api_user), class: 'btn btn-primary btn-xs') - - .table-responsive - %table.table.table-hover.table-bordered.table-condensed - %thead - %tr - %th{class: 'col-xs-10'}= t('.subject') - %th{class: 'col-xs-2'}= t(:status) - %tbody - - @api_user.certificates.each do |x| - - if x.csr - %tr - %td= link_to(x.parsed_csr.try(:subject), admin_api_user_certificate_path(@api_user, x)) - %td= x.status - - elsif x.crt - %tr - %td= link_to(x.parsed_crt.try(:subject), admin_api_user_certificate_path(@api_user, x)) - %td= x.status diff --git a/app/views/admin/api_users/show.html.erb b/app/views/admin/api_users/show.html.erb new file mode 100644 index 000000000..05c5651ce --- /dev/null +++ b/app/views/admin/api_users/show.html.erb @@ -0,0 +1,37 @@ + + + + +
+
+ <%= render 'admin/api_users/show/details' %> +
+
+ +
+
+ <%= render 'admin/api_users/show/certificates' %> +
+
diff --git a/app/views/admin/api_users/show/_certificates.html.erb b/app/views/admin/api_users/show/_certificates.html.erb new file mode 100644 index 000000000..75a3cc2df --- /dev/null +++ b/app/views/admin/api_users/show/_certificates.html.erb @@ -0,0 +1,55 @@ +
+
+
+ <%= t(:certificates) %> +
+ +
+ <%= link_to(t(:upload_crt), new_admin_api_user_certificate_path(@api_user, crt: true), class: 'btn btn-primary btn-xs') %> + <%= link_to(t(:upload_csr), new_admin_api_user_certificate_path(@api_user), class: 'btn btn-primary btn-xs') %> +
+
+ +
+ + + + + + + + + + <% @api_user.certificates.each do |x| %> + <% if x.csr %> + + + + + <% elsif x.crt %> + + + + + <% end %> + <% end %> + +
+ <%= t('.subject') %> + + <%= t(:status) %> +
+ <%= link_to(x.parsed_csr.try(:subject), + admin_api_user_certificate_path(@api_user, + x)) %> + + <%= x.status %> +
+ <%= link_to(x.parsed_crt.try(:subject), + admin_api_user_certificate_path(@api_user, + x)) %> + + <%= x.status %> +
+
+
diff --git a/app/views/admin/api_users/show/_details.html.erb b/app/views/admin/api_users/show/_details.html.erb new file mode 100644 index 000000000..c98f23866 --- /dev/null +++ b/app/views/admin/api_users/show/_details.html.erb @@ -0,0 +1,26 @@ +
+
+

+ <%= t '.header' %> +

+
+ +
+
+
<%= ApiUser.human_attribute_name :username %>
+
<%= @api_user.username %>
+ +
<%= ApiUser.human_attribute_name :plain_text_password %>
+
<%= @api_user.plain_text_password %>
+ +
<%= Registrar.model_name.human %>
+
<%= link_to(@api_user.registrar, admin_registrar_path(@api_user.registrar)) %>
+ +
<%= ApiUser.human_attribute_name :roles %>
+
<%= @api_user.roles.join(', ') %>
+ +
<%= ApiUser.human_attribute_name :active %>
+
<%= @api_user.active %>
+
+
+
diff --git a/app/views/admin/base/_menu.haml b/app/views/admin/base/_menu.haml index fa1b50440..a327419fd 100644 --- a/app/views/admin/base/_menu.haml +++ b/app/views/admin/base/_menu.haml @@ -32,10 +32,11 @@ %li= link_to t('.zones'), admin_zones_path %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('.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' %ul.nav.navbar-nav.navbar-right %li= link_to t('.sign_out'), destroy_admin_user_session_path, method: :delete, - class: 'navbar-link' \ No newline at end of file + class: 'navbar-link' diff --git a/app/views/admin/certificates/show.haml b/app/views/admin/certificates/show.haml index 821d7ec9a..30d095f65 100644 --- a/app/views/admin/certificates/show.haml +++ b/app/views/admin/certificates/show.haml @@ -20,7 +20,7 @@ .panel-body %dl.dl-horizontal %dt= t(:api_user) - %dd= link_to(@certificate.api_user, [:admin, @api_user]) + %dd= link_to(@certificate.api_user, [:admin, @api_user.registrar, @api_user]) %dt= t(:common_name) %dd= @certificate.common_name diff --git a/app/views/admin/contacts/index.haml b/app/views/admin/contacts/index.haml index cc80ac744..cbd11d3fc 100644 --- a/app/views/admin/contacts/index.haml +++ b/app/views/admin/contacts/index.haml @@ -63,6 +63,10 @@ .form-group = label_tag :only_no_country_code, "Ident CC missing" = check_box_tag :only_no_country_code, '1',params[:only_no_country_code].eql?('1'), style: 'width:auto;height:auto;float:right' + .col-md-3 + .form-group + = label_tag :email_verification_failed, "Email verification failed" + = check_box_tag :email_verification_failed, '1',params[:email_verification_failed].eql?('1'), style: 'width:auto;height:auto;float:right' .row .col-md-3{style: 'padding-top: 25px;float:right;'} @@ -85,7 +89,9 @@ %th{class: 'col-xs-2'} = sort_link(@q, 'ident', t(:ident)) %th{class: 'col-xs-2'} - = sort_link(@q, 'email', t(:created_at)) + = sort_link(@q, 'email', t(:email)) + %th{class: 'col-xs-2'} + = sort_link(@q, 'created_at', t(:created_at)) %th{class: 'col-xs-2'} = sort_link(@q, 'registrar_name', t(:registrar_name)) %tbody @@ -94,6 +100,7 @@ %td= link_to(contact, admin_contact_path(contact)) %td= contact.code %td= ident_for(contact) + %td= verified_email_span(contact.email_verification) %td= l(contact.created_at, format: :short) %td - if contact.registrar diff --git a/app/views/admin/contacts/partials/_domains.haml b/app/views/admin/contacts/partials/_domains.haml index 3a60074d1..91b0715ba 100644 --- a/app/views/admin/contacts/partials/_domains.haml +++ b/app/views/admin/contacts/partials/_domains.haml @@ -1,4 +1,5 @@ -- domains = contact.all_domains(page: params[:domain_page], per: 20, params: params) +- domains = contact.all_domains(page: params[:domain_page], per: 20, + params: domain_filter_params.to_h) .panel.panel-default .panel-heading .pull-left diff --git a/app/views/admin/contacts/partials/_general.haml b/app/views/admin/contacts/partials/_general.haml index 029f89509..6568cd3d0 100644 --- a/app/views/admin/contacts/partials/_general.haml +++ b/app/views/admin/contacts/partials/_general.haml @@ -17,7 +17,7 @@ %dd= ident_for(@contact) %dt= t(:email) - %dd= @contact.email + %dd= verified_email_span(@contact.email_verification) %dt= t(:phone) %dd= @contact.phone diff --git a/app/views/admin/disputes/_form.html.erb b/app/views/admin/disputes/_form.html.erb new file mode 100644 index 000000000..2a3fb722f --- /dev/null +++ b/app/views/admin/disputes/_form.html.erb @@ -0,0 +1,60 @@ +<%= form_for([:admin, @dispute], html: { class: 'form-horizontal' }) do |f| %> + <%= render 'shared/full_errors', object: @dispute %> + +
+
+
+
+
+ <%= t(:general) %> +
+
+
+
+

As per domain law, expiry time is <%= Setting.dispute_period_in_months / 12 %> years ahead from start date.

+
+
+
+ <%= f.label :domain_name %> +
+
+ <%= f.text_field(:domain_name, class: 'form-control', disabled: !f.object.new_record?) %> +
+
+
+
+ <%= f.label :password %> +
+
+ <%= f.text_field(:password, placeholder: t(:optional), class: 'form-control') %> + <%= t '.password_hint' %> +
+
+
+
+ <%= f.label :starts_at %> +
+
+ <%= f.text_field(:starts_at, class: 'form-control js-datepicker') %> + <%= t '.past_or_today' %> +
+
+
+
+ <%= f.label :comment %> +
+
+ <%= f.text_field(:comment, placeholder: t(:optional), class: 'form-control') %> +
+
+
+
+
+
+ +
+
+ <%= button_tag(t(:save), class: 'btn btn-primary') %> +
+
+<% end %> diff --git a/app/views/admin/disputes/edit.haml b/app/views/admin/disputes/edit.haml new file mode 100644 index 000000000..966976891 --- /dev/null +++ b/app/views/admin/disputes/edit.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:edit_dispute) + += render 'form' diff --git a/app/views/admin/disputes/index.html.erb b/app/views/admin/disputes/index.html.erb new file mode 100644 index 000000000..e32ddb730 --- /dev/null +++ b/app/views/admin/disputes/index.html.erb @@ -0,0 +1,175 @@ +<% content_for :actions do %> +<%= link_to(t('.new_btn'), new_admin_dispute_path, class: 'btn btn-primary') %> +<% end %> +<%= render 'shared/title', name: t('.title') %> +
+
+ <%= search_form_for [:admin, @q], html: { style: 'margin-bottom: 0;', class: 'js-form', autocomplete: 'off' } do |f| %> +
+
+
+ <%= f.label :domain_name %> + <%= f.search_field :domain_name_matches, value: params[:q][:domain_name_matches], class: 'form-control', placeholder: t(:name) %> +
+
+
+
+ <%= f.label t(:created_at_from) %> + <%= f.search_field :created_at_gteq, value: params[:q][:created_at_gteq], class: 'form-control js-datepicker', placeholder: t(:created_at_from) %> +
+
+
+
+ <%= f.label t(:created_at_until) %> + <%= f.search_field :created_at_lteq, value: params[:q][:created_at_lteq], class: 'form-control js-datepicker', placeholder: t(:created_at_until) %> +
+
+
+
+
+
+ <%= label_tag t(:results_per_page) %> + <%= text_field_tag :results_per_page, params[:results_per_page], class: 'form-control', placeholder: t(:results_per_page) %> +
+
+
+ + <%= link_to(t('.reset_btn'), admin_disputes_path, class: 'btn btn-default') %> +
+
+ <% end %> +
+
+
+

Active disputes

+
+
+
+ + + + + + + + + + + + + <% @disputes.each do |x| %> + + + + + + + + + <% end %> + +
+ <%= sort_link(@q, 'domain_name') %> + + <%= sort_link(@q, 'password') %> + + <%= sort_link(@q, 'starts_at') %> + + <%= sort_link(@q, 'expires_at') %> + + <%= sort_link(@q, 'comment') %> + + <%= t(:actions) %> +
+ <%= x.domain_name %> + + <%= x.password %> + + <%= x.starts_at %> + + <%= x.expires_at %> + + <%= x.comment %> + + <%= link_to t(:edit), edit_admin_dispute_path(id: x.id), + class: 'btn btn-primary btn-xs' %> + <%= link_to t(:delete), delete_admin_dispute_path(id: x.id), + data: { confirm: t(:are_you_sure) }, class: 'btn btn-danger btn-xs' %> +
+
+
+
+
+
+ <%= paginate @disputes %> +
+
+ +
+
+
+

Expired / Closed disputes

+
+
+
+ + + + + + + + + + + + <% @closed_disputes.each do |x| %> + + + + + + + + <% end %> + +
+ <%= sort_link(@q, 'domain_name') %> + + <%= sort_link(@q, 'initiator') %> + + <%= sort_link(@q, 'starts_at') %> + + <%= sort_link(@q, 'closed') %> + + <%= sort_link(@q, 'comment') %> +
+ <%= x.domain_name %> + + <%= x.initiator %> + + <%= x.starts_at %> + + <%= x.closed %> + + <%= x.comment %> +
+
+
+
+
+
+ <%= paginate @closed_disputes, param_name: :closed_page %> +
+
+ +
+
diff --git a/app/views/admin/disputes/new.haml b/app/views/admin/disputes/new.haml new file mode 100644 index 000000000..0a57af7be --- /dev/null +++ b/app/views/admin/disputes/new.haml @@ -0,0 +1,3 @@ += render 'shared/title', name: t(:add_disputed_domain) + += render 'form' diff --git a/app/views/admin/domains/_force_delete_dialog.html.erb b/app/views/admin/domains/_force_delete_dialog.html.erb index 26edf3756..a76c14edd 100644 --- a/app/views/admin/domains/_force_delete_dialog.html.erb +++ b/app/views/admin/domains/_force_delete_dialog.html.erb @@ -10,6 +10,17 @@ <%= form_tag admin_domain_force_delete_path(domain), id: 'domain-force-delete-form', class: 'modal-body form-horizontal' do %> +
+
+
+ +
+
+
+
diff --git a/app/views/admin/invoices/show.haml b/app/views/admin/invoices/show.haml index e3627c158..d0450469f 100644 --- a/app/views/admin/invoices/show.haml +++ b/app/views/admin/invoices/show.haml @@ -21,3 +21,5 @@ .col-md-6= render 'registrar/invoices/partials/buyer' .row .col-md-12= render 'registrar/invoices/partials/items' +.row + .col-md-12= render 'registrar/invoices/partials/payment_orders' diff --git a/app/views/admin/registrars/_form.html.erb b/app/views/admin/registrars/_form.html.erb index 5545adef1..19866a31f 100644 --- a/app/views/admin/registrars/_form.html.erb +++ b/app/views/admin/registrars/_form.html.erb @@ -91,6 +91,24 @@ <%= f.check_box :test_registrar, class: 'form-control' %>
+ +
+
+ <%= f.label t('.legaldoc_optout') %> +
+
+ <%= f.check_box :legaldoc_optout, class: 'form-control' %> +
+
+ +
+
+ <%= f.label t('.legaldoc_optout_comment') %> +
+
+ <%= f.text_area :legaldoc_optout_comment, class: 'form-control', rows: 3 %> +
+
diff --git a/app/views/admin/registrars/index.html.erb b/app/views/admin/registrars/index.html.erb index a66816568..e641f5294 100644 --- a/app/views/admin/registrars/index.html.erb +++ b/app/views/admin/registrars/index.html.erb @@ -28,6 +28,9 @@ <%= t(:test_registrar) %> + + <%= t(:emails) %> + @@ -45,6 +48,12 @@ <%= "#{x.test_registrar}" %> + + <%= verified_email_span(x.email_verification) %> + <% if x[:billing_email].present? %> + <%= verified_email_span(x.billing_email_verification) %> + <% end %> + <% end %> diff --git a/app/views/admin/registrars/show.html.erb b/app/views/admin/registrars/show.html.erb index 62e7a5df1..2da2c84ce 100644 --- a/app/views/admin/registrars/show.html.erb +++ b/app/views/admin/registrars/show.html.erb @@ -39,7 +39,7 @@
- <%= render 'admin/registrars/show/users', registrar: @registrar %> + <%= render 'admin/registrars/show/api_users', registrar: @registrar %>
diff --git a/app/views/admin/registrars/show/_users.html.erb b/app/views/admin/registrars/show/_api_users.html.erb similarity index 76% rename from app/views/admin/registrars/show/_users.html.erb rename to app/views/admin/registrars/show/_api_users.html.erb index f182e4615..2d10b1c56 100644 --- a/app/views/admin/registrars/show/_users.html.erb +++ b/app/views/admin/registrars/show/_api_users.html.erb @@ -12,10 +12,10 @@ - <% registrar.api_users.each do |user| %> + <% registrar.api_users.each do |api_user| %> - <%= link_to(user, [:admin, user]) %> - <%= user.active %> + <%= link_to api_user, admin_registrar_api_user_path(api_user.registrar, api_user) %> + <%= api_user.active %> <% end %> diff --git a/app/views/admin/registrars/show/_billing.html.erb b/app/views/admin/registrars/show/_billing.html.erb index da79b9074..07bccc7f4 100644 --- a/app/views/admin/registrars/show/_billing.html.erb +++ b/app/views/admin/registrars/show/_billing.html.erb @@ -15,7 +15,9 @@
<%= registrar.accounting_customer_code %>
<%= Registrar.human_attribute_name :billing_email %>
-
<%= registrar.billing_email %>
+
+ <%= verified_email_span(registrar.billing_email_verification) %> +
<%= Registrar.human_attribute_name :reference_no %>
<%= registrar.reference_no %>
@@ -24,4 +26,4 @@
<%= registrar.iban %>
- \ No newline at end of file + diff --git a/app/views/admin/registrars/show/_contacts.html.erb b/app/views/admin/registrars/show/_contacts.html.erb index f467e6a51..0ca1158d3 100644 --- a/app/views/admin/registrars/show/_contacts.html.erb +++ b/app/views/admin/registrars/show/_contacts.html.erb @@ -15,7 +15,9 @@
<%= @registrar.phone %>
<%= Registrar.human_attribute_name :email %>
-
<%= @registrar.email %>
+
+ <%= verified_email_span(@registrar.email_verification) %> +
- \ No newline at end of file + diff --git a/app/views/admin/settings/index.haml b/app/views/admin/settings/index.haml index 23f87c4b2..9eb236b65 100644 --- a/app/views/admin/settings/index.haml +++ b/app/views/admin/settings/index.haml @@ -22,6 +22,7 @@ = render 'setting_row', var: :ns_min_count = render 'setting_row', var: :ns_max_count = render 'setting_row', var: :expire_pending_confirmation + = render 'setting_row', var: :legal_document_is_mandatory .panel.panel-default .panel-heading @@ -48,7 +49,7 @@ = render 'setting_row', var: :request_confrimation_on_registrant_change_enabled = render 'setting_row', var: :request_confirmation_on_domain_deletion_enabled = render 'setting_row', var: :address_processing - + = render 'setting_row', var: :dispute_period_in_months %tr %td.col-md-6= label_tag :default_language %td.col-md-6 diff --git a/app/views/epp/contacts/info.xml.builder b/app/views/epp/contacts/info.xml.builder index 38a96a706..1945e7def 100644 --- a/app/views/epp/contacts/info.xml.builder +++ b/app/views/epp/contacts/info.xml.builder @@ -65,14 +65,9 @@ xml.epp_head do xml.tag!('contact:upID', upID) if upID.present? # optional upID xml.tag!('contact:upDate', @contact.updated_at.try(:iso8601)) end - # xml.tag!('contact:trDate', '123') if false if can? :view_password, @contact, @password xml.tag!('contact:authInfo') do - xml.tag!('contact:pw', @contact.auth_info) - end - else - xml.tag!('contact:authInfo') do - xml.tag!('contact:pw', 'No access') + xml.tag!('contact:pw', @contact.auth_info) end end end diff --git a/app/views/layouts/admin/base.haml b/app/views/layouts/admin/base.haml index 792a8cc0b..928629ce6 100644 --- a/app/views/layouts/admin/base.haml +++ b/app/views/layouts/admin/base.haml @@ -32,5 +32,5 @@ .footer.text-right Version - = CURRENT_COMMIT_HASH + = current_commit_link = javascript_include_tag 'admin-manifest', async: true diff --git a/app/views/layouts/registrant/application.html.erb b/app/views/layouts/registrant/application.html.erb index 66fdf3e16..c5290b70f 100644 --- a/app/views/layouts/registrant/application.html.erb +++ b/app/views/layouts/registrant/application.html.erb @@ -76,7 +76,7 @@
Version - <%= CURRENT_COMMIT_HASH %> + <%= current_commit_link %>
diff --git a/app/views/layouts/registrar/base.html.erb b/app/views/layouts/registrar/base.html.erb index 4d4f1b972..5881dd400 100644 --- a/app/views/layouts/registrar/base.html.erb +++ b/app/views/layouts/registrar/base.html.erb @@ -54,7 +54,7 @@
Version - <%= CURRENT_COMMIT_HASH %> + <%= current_commit_link %>
diff --git a/app/views/layouts/registrar/sessions.html.erb b/app/views/layouts/registrar/sessions.html.erb index 3cb345ef9..ace645199 100644 --- a/app/views/layouts/registrar/sessions.html.erb +++ b/app/views/layouts/registrar/sessions.html.erb @@ -44,7 +44,7 @@
Version - <%= CURRENT_COMMIT_HASH %> + <%= current_commit_link %>
diff --git a/app/views/mailers/domain_delete_mailer/forced/legal_person.html.erb b/app/views/mailers/domain_delete_mailer/forced/legal_person.html.erb index 4a4877767..39bedde9b 100644 --- a/app/views/mailers/domain_delete_mailer/forced/legal_person.html.erb +++ b/app/views/mailers/domain_delete_mailer/forced/legal_person.html.erb @@ -2,11 +2,11 @@

Eesti Interneti Sihtasutusele on saanud teatavaks, et juriidiline isik registrikoodiga <%= @registrant.reg_no %> on äriregistrist kustutatud.

-

Kuna äriregistrist kustutatud juriidiline isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @redemption_grace_period %> päevane kustutusmenetlus. Menetluse käigus on domeen internetis kättesaadav.

+

Kuna äriregistrist kustutatud juriidiline isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @delete_period_length %> päevane kustutusmenetlus. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav.

Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus koos seda tõendava dokumendiga.

-

Kui üleandmine ei ole <%= @redemption_grace_period %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit.

+

Kui üleandmine ei ole <%= @delete_period_length %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit.

Lisaküsimuste korral võtke palun ühendust oma registripidajaga:

<%= render 'mailers/shared/registrar/registrar.et.html', registrar: @registrar %> @@ -19,11 +19,11 @@

Estonian Internet Foundation has learned that the legal person with registry code <%= @registrant.reg_no %> has been deleted from the Business Registry.

-

As a terminated legal person cannot be the registrant of a domain, a <%= @redemption_grace_period %>-day deletion process has started for the <%= @domain.name %> domain. The domain will remain available on the Internet during the deletion process.

+

As a terminated legal person cannot be the registrant of a domain, a <%= @delete_period_length %>-day deletion process has started for the <%= @domain.name %> domain. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process.

The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %> with legal documentation.

-

If the transfer is not made within <%= @redemption_grace_period %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction portal. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results.

+

If the transfer is not made within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction portal. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results.

Should you have additional questions, please contact your registrar:

<%= render 'mailers/shared/registrar/registrar.en.html', registrar: @registrar %> @@ -35,13 +35,13 @@

Целевому учреждению Eesti Internet (EIS) стало известно, что юридическое лицо с регистрационным кодом <%= @registrant.reg_no %> удалено из коммерческого реестра.

-

Поскольку удаленное из коммерческого регистра юридическое лицо не может являться регистрантом домена, начат <%= @redemption_grace_period %>-дневный процесс удаления домена <%= @domain.name %>. До завершения процесса домен доступен в Интернете.

+

Поскольку удаленное из коммерческого регистра юридическое лицо не может являться регистрантом домена, начат <%= @delete_period_length %>-дневный процесс удаления домена <%= @domain.name %>. Домен доступен в интернете на протяжении <%= @expire_warning_period %> дней после начала процесса удаления.

-

Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче домена, представив вместе с ходатайством подтверждающие документы. Документы должны быть представлены регистратору в течение <%= @redemption_grace_period %> дней.

+

Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче домена, представив вместе с ходатайством подтверждающие документы. Документы должны быть представлены регистратору в течение <%= @delete_period_length %> дней.

-

Если передача не состоится в течение <%= @redemption_grace_period %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». Читайте о других возможных результатах аукциона.

+

Если передача не состоится в течение <%= @delete_period_length %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». Читайте о других возможных результатах аукциона.

В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором: <%= render 'mailers/shared/registrar/registrar.ru.html', registrar: @registrar %>

-<%= render 'mailers/shared/signatures/signature.ru.html' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.html' %> diff --git a/app/views/mailers/domain_delete_mailer/forced/legal_person.text.erb b/app/views/mailers/domain_delete_mailer/forced/legal_person.text.erb index 31d13b9f9..fb2bc5d6c 100644 --- a/app/views/mailers/domain_delete_mailer/forced/legal_person.text.erb +++ b/app/views/mailers/domain_delete_mailer/forced/legal_person.text.erb @@ -2,11 +2,11 @@ Lugupeetud domeeni <%= @domain.name %> registreerija/halduskontakt Eesti Interneti Sihtasutusele on saanud teatavaks, et juriidiline isik registrikoodiga <%= @registrant.reg_no %> on äriregistrist kustutatud. -Kuna äriregistrist kustutatud juriidiline isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @redemption_grace_period %> päevane kustutusmenetlus. Menetluse käigus on domeen internetis kättesaadav. +Kuna äriregistrist kustutatud juriidiline isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @delete_period_length %> päevane kustutusmenetlus. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav. Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus koos seda tõendava dokumendiga. -Kui üleandmine ei ole <%= @redemption_grace_period %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda https://auction.internet.ee. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. +Kui üleandmine ei ole <%= @delete_period_length %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda https://auction.internet.ee. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. Lisaküsimuste korral võtke palun ühendust oma registripidajaga: <%= render 'mailers/shared/registrar/registrar.et.text', registrar: @registrar %> @@ -19,11 +19,11 @@ Dear registrant/administrative contact of .ee domain, Estonian Internet Foundation has learned that the legal person with registry code <%= @registrant.reg_no %> has been deleted from the Business Registry. -As a terminated legal person cannot be the registrant of a domain, a <%= @redemption_grace_period %>-day deletion process has started for the <%= @domain.name %> domain. The domain will remain available on the Internet during the deletion process. +As a terminated legal person cannot be the registrant of a domain, a <%= @delete_period_length %>-day deletion process has started for the <%= @domain.name %> domain. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process. The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %> with legal documentation. -If the transfer is not made within <%= @redemption_grace_period %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction portal https://auction.internet.ee. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. +If the transfer is not made within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction portal https://auction.internet.ee. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. Should you have additional questions, please contact your registrar: <%= render 'mailers/shared/registrar/registrar.en.text', registrar: @registrar %> @@ -36,13 +36,13 @@ Should you have additional questions, please contact your registrar: Целевому учреждению Eesti Internet (EIS) стало известно, что юридическое лицо с регистрационным кодом <%= @registrant.reg_no %> удалено из коммерческого реестра. -Поскольку удаленное из коммерческого регистра юридическое лицо не может являться регистрантом домена, начат <%= @redemption_grace_period %>-дневный процесс удаления домена <%= @domain.name %>. До завершения процесса домен доступен в Интернете. +Поскольку удаленное из коммерческого регистра юридическое лицо не может являться регистрантом домена, начат <%= @delete_period_length %>-дневный процесс удаления домена <%= @domain.name %>. Домен доступен в интернете на протяжении <%= @expire_warning_period %> дней после начала процесса удаления.

-Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче домена, представив вместе с ходатайством подтверждающие документы. Документы должны быть представлены регистратору в течение <%= @redemption_grace_period %> дней. +Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче домена, представив вместе с ходатайством подтверждающие документы. Документы должны быть представлены регистратору в течение <%= @delete_period_length %> дней. -Если передача не состоится в течение <%= @redemption_grace_period %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee https://auction.internet.ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте по ссылке https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. +Если передача не состоится в течение <%= @delete_period_length %>дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee https://auction.internet.ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте по ссылке https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором: <%= render 'mailers/shared/registrar/registrar.ru.text', registrar: @registrar %> -<%= render 'mailers/shared/signatures/signature.ru.text' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.text' %> diff --git a/app/views/mailers/domain_delete_mailer/forced/private_person.html.erb b/app/views/mailers/domain_delete_mailer/forced/private_person.html.erb index 2a7144d2c..947ff5c2b 100644 --- a/app/views/mailers/domain_delete_mailer/forced/private_person.html.erb +++ b/app/views/mailers/domain_delete_mailer/forced/private_person.html.erb @@ -2,11 +2,11 @@

Eesti Interneti Sihtasutusele (EIS) on saanud teatavaks, et füüsiline isik isikukoodiga <%= @registrant.id_code %> on surnud ja sellest on möödunud vähemalt 6 kuud.

-

Kuna surnud isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @redemption_grace_period %> päevane kustutusmenetlus. Menetluse käigus on domeen internetis kättesaadav.

+

Kuna surnud isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @delete_period_length %> päevane kustutusmenetlus. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav.

-

Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus, millele tuleb lisada pärimisõiguse tõend. Dokumentatsioon tuleb esitada registripidajale <%= @redemption_grace_period %> päeva jooksul.

+

Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus, millele tuleb lisada pärimisõiguse tõend. Dokumentatsioon tuleb esitada registripidajale <%= @delete_period_length %> päeva jooksul.

-

Kui üleandmine ei ole <%= @redemption_grace_period %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit.

+

Kui üleandmine ei ole <%= @delete_period_length %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit.

Lisaküsimuste korral võtke palun ühendust oma registripidajaga:

<%= render 'mailers/shared/registrar/registrar.et.html', registrar: @registrar %> @@ -19,11 +19,11 @@

Estonian Internet Foundation (EIF) has learned that the natural person with identification code <%= @registrant.id_code %> has been deceased more than 6 months.

-

The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %>.The application must be submitted together with succession evidence certifying the acquisition of the domain. The relevant documents should be submitted to the registrar within <%= @redemption_grace_period %> days.

+

The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %>.The application must be submitted together with succession evidence certifying the acquisition of the domain. The relevant documents should be submitted to the registrar within <%= @delete_period_length %> days.

-

As a deceased natural person can not be the registrant of a domain, a <%= @redemption_grace_period %>-day deletion process of <%= @domain.name %> domain has started. The domain will remain available on the Internet during the deletion process.

+

As a deceased natural person can not be the registrant of a domain, a <%= @delete_period_length %>-day deletion process of <%= @domain.name %> domain has started. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process.

-

If the transfer is not made within <%= @redemption_grace_period %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction environment. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results.

+

If the transfer is not made within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction environment. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results.

Should you have additional questions, please contact your registrar:

<%= render 'mailers/shared/registrar/registrar.en.html', registrar: @registrar %> @@ -36,13 +36,13 @@

Целевому учреждению Eesti Internet (EIS) стало известно, что физическое лицо с личным кодом <%= @registrant.id_code %> умерло, и с момента смерти прошло не менее 6 месяцев.

-

Поскольку умершее лицо не может являться регистрантом домена, начат <%= @redemption_grace_period %>-дневный процесс удаления домена <%= @domain.name %>. До завершения процесса домен доступен в Интернете.

+

Поскольку умершее лицо не может являться регистрантом домена, начат <%= @delete_period_length %>-дневный процесс удаления домена <%= @domain.name %>. Домен доступен в интернете на протяжении <%= @expire_warning_period %> дней после начала процесса удаления.

-

Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче, представив справку о праве наследования. Документы должны быть представлены регистратору в течение <%= @redemption_grace_period %> дней.

+

Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче, представив справку о праве наследования. Документы должны быть представлены регистратору в течение <%= @delete_period_length %> дней.

-

Если передача не состоится в течение <%= @redemption_grace_period %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». Читайте о других возможных результатах аукциона.

+

Если передача не состоится в течение <%= @delete_period_length %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». Читайте о других возможных результатах аукциона.

В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором:

<%= render 'mailers/shared/registrar/registrar.ru.html', registrar: @registrar %> -<%= render 'mailers/shared/signatures/signature.ru.html' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.html' %> diff --git a/app/views/mailers/domain_delete_mailer/forced/private_person.text.erb b/app/views/mailers/domain_delete_mailer/forced/private_person.text.erb index 9a8971b19..bb315e48b 100644 --- a/app/views/mailers/domain_delete_mailer/forced/private_person.text.erb +++ b/app/views/mailers/domain_delete_mailer/forced/private_person.text.erb @@ -2,11 +2,11 @@ Lugupeetud domeeni <%= @domain.name %> registreerija/halduskontakt Eesti Interneti Sihtasutusele (EIS) on saanud teatavaks, et füüsiline isik isikukoodiga <%= @registrant.id_code %> on surnud ja sellest on möödunud vähemalt 6 kuud. -Kuna surnud isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @redemption_grace_period %> päevane kustutusmenetlus. Menetluse käigus on domeen internetis kättesaadav. +Kuna surnud isik ei saa olla domeeni registreerijaks, algas domeeni <%= @domain.name %> suhtes <%= @delete_period_length %> päevane kustutusmenetlus. Menetluse käigus on domeen <%= @expire_warning_period %> esimest päeva internetis kättesaadav. -Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus, millele tuleb lisada pärimisõiguse tõend. Dokumentatsioon tuleb esitada registripidajale <%= @redemption_grace_period %> päeva jooksul. +Domeeni suhtes õigust omaval isikul on võimalus esitada domeeni <%= @domain.name %> registripidajale <%= @registrar.name %> domeeni üleandmise taotlus, millele tuleb lisada pärimisõiguse tõend. Dokumentatsioon tuleb esitada registripidajale <%= @delete_period_length %> päeva jooksul. -Kui üleandmine ei ole <%= @redemption_grace_period %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda https://auction.internet.ee. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. +Kui üleandmine ei ole <%= @delete_period_length %> päeva jooksul toimunud, läheb domeen <%= @domain.name %> <%= @domain.force_delete_date %> domeenioksjonile .ee oksjonikeskkonda https://auction.internet.ee. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. Lisaküsimuste korral võtke palun ühendust oma registripidajaga: <%= render 'mailers/shared/registrar/registrar.et.text', registrar: @registrar %> @@ -19,11 +19,11 @@ Dear registrant/administrative contact of <%= @domain.name %> domain Estonian Internet Foundation (EIF) has learned that the natural person with identification code <%= @registrant.id_code %> has been deceased more than 6 months. -The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %>.The application must be submitted together with succession evidence certifying the acquisition of the domain. The relevant documents should be submitted to the registrar within <%= @redemption_grace_period %> days. +The registrant holding a right to the domain name <%= @domain.name %> can submit a domain name transfer application to the registrar <%= @registrar.name %>.The application must be submitted together with succession evidence certifying the acquisition of the domain. The relevant documents should be submitted to the registrar within <%= @delete_period_length %> days. -As a deceased natural person can not be the registrant of a domain, a <%= @redemption_grace_period %>-day deletion process of <%= @domain.name %> domain has started. The domain will remain available on the Internet during the deletion process. +As a deceased natural person can not be the registrant of a domain, a <%= @delete_period_length %>-day deletion process of <%= @domain.name %> domain has started. For the first <%= @expire_warning_period %> days the domain will remain available on the Internet during the deletion process. -If the transfer is not made within <%= @redemption_grace_period %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction environment at https://auction.internet.ee. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. +If the transfer is not made within <%= @delete_period_length %> days, the domain <%= @domain.name %> will go to domain auction on <%= @domain.force_delete_date %> in the .ee auction environment at https://auction.internet.ee. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. Should you have additional questions, please contact your registrar: <%= render 'mailers/shared/registrar/registrar.en.text', registrar: @registrar %> @@ -36,13 +36,13 @@ Should you have additional questions, please contact your registrar: Целевому учреждению Eesti Internet (EIS) стало известно, что физическое лицо с личным кодом <%= @registrant.id_code %> умерло, и с момента смерти прошло не менее 6 месяцев. -Поскольку умершее лицо не может являться регистрантом домена, начат <%= @redemption_grace_period %>-дневный процесс удаления домена <%= @domain.name %>. До завершения процесса домен доступен в Интернете. +Поскольку умершее лицо не может являться регистрантом домена, начат <%= @delete_period_length %>-дневный процесс удаления домена <%= @domain.name %>. Домен доступен в интернете на протяжении <%= @expire_warning_period %> дней после начала процесса удаления. -Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче, представив справку о праве наследования. Документы должны быть представлены регистратору в течение <%= @redemption_grace_period %> дней. +Лицо, обладающее правом на домен, может подать регистратору <%= @registrar.name %> домена <%= @domain.name %> ходатайство о передаче, представив справку о праве наследования. Документы должны быть представлены регистратору в течение <%= @delete_period_length %> дней. -Если передача не состоится в течение <%= @redemption_grace_period %> дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee https://auction.internet.ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте по ссылке https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. +Если передача не состоится в течение <%= @delete_period_length %>дней, <%= @domain.force_delete_date %> домен <%= @domain.name %> отправится на доменный аукцион в аукционной среде .ee https://auction.internet.ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте по ссылке https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. В случае возникновения дополнительных вопросов свяжитесь, пожалуйста, со своим регистратором: <%= render 'mailers/shared/registrar/registrar.ru.text', registrar: @registrar %> -<%= render 'mailers/shared/signatures/signature.ru.text' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.text' %> diff --git a/app/views/mailers/domain_expire_mailer/expired.html.erb b/app/views/mailers/domain_expire_mailer/expired.html.erb index 58043c7ce..f04301245 100644 --- a/app/views/mailers/domain_expire_mailer/expired.html.erb +++ b/app/views/mailers/domain_expire_mailer/expired.html.erb @@ -2,9 +2,11 @@

Lugupeetud .ee domeeni registreerija/halduskontakt

-

Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeen <%= @domain.name %> on <%= @domain.delete_date %> domeenioksjonil .ee oksjonikeskkonnas. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit.

+

Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Registreeringu pikendamiseks pöörduge palun oma registripidaja poole.

-

Domeeni registreeringu pikendamiseks pöörduge palun oma registripidaja poole:

+

<%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt siit.

+ +

Domeeni <%= @domain.name %> registripidaja:

<%= render 'mailers/shared/registrar/registrar.et.html', registrar: @registrar %>

Ülevaate kõikidest endaga seotud domeenidest saate registreerija portaalist.

@@ -17,9 +19,11 @@

Dear registrant/administrative contact of .ee domain,

-

The domain name <%= @domain.name %> has expired and since <%= @domain.on_hold_date %> is no longer available on the Internet. The domain <%= @domain.name %> will be available for domain auction on <%= @domain.delete_date %> in the .ee auction portal. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results.

+

The domain name <%= @domain.name %> has expired and since <%= @domain.on_hold_date %> is no longer available on the Internet. To renew your domain registration, please contact your registrar.

-

To renew your domain registration, please contact your registrar:

+

If you do not renew the <%= @domain.name %> domain registration, it is deleted and put on auction to .ee domain auction environment at <%= @domain.delete_date %>. Read more about .ee domain auctions here.

+ +

Registrar of the <%= @domain.name %>:

<%= render 'mailers/shared/registrar/registrar.en.html', registrar: @registrar %>

You can find an overview of all your domains at the registrant's portal.

@@ -32,11 +36,13 @@

Уважаемый регистрант/административный контакт домена .ee

-

Срок действия доменного имени <%= @domain.name %> истек, и с <%= @domain.on_hold_date %> оно больше не доступно в интернете. <%= @domain.delete_date %> домен <%= @domain.name %> будет представлен на доменном аукционе в аукционной среде .ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». Читайте о других возможных результатах аукциона.

+

Срок действия доменного имени <%= @domain.name %> истек, и с <%= @domain.on_hold_date %> оно больше не доступно в интернете. Для продления регистрации домена обратитесь пожалуйста к своему регистратору.

-

Для продления регистрации домена обратитесь, пожалуйста, к своему регистратору:

+

Если доменное имя не продлено, домен <%= @domain.name %> будет удален и <%= @domain.delete_date %> идет на аукцион в .ee среду аукциона. О других возможных результатах аукциона читайте здесь.

+ +

Pегистратор домена <%= @domain.name %>:

<%= render 'mailers/shared/registrar/registrar.ru.html', registrar: @registrar %>

Обзор всех связанных с вами доменов можете получить на портале регистратора.

-<%= render 'mailers/shared/signatures/signature.ru.html' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.html' %> diff --git a/app/views/mailers/domain_expire_mailer/expired.text.erb b/app/views/mailers/domain_expire_mailer/expired.text.erb index 7bd0ffde6..634746493 100644 --- a/app/views/mailers/domain_expire_mailer/expired.text.erb +++ b/app/views/mailers/domain_expire_mailer/expired.text.erb @@ -2,9 +2,11 @@ Domeen <%= @domain.name %> on aegunud Lugupeetud .ee domeeni registreerija/halduskontakt -Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeen <%= @domain.name %> on <%= @domain.delete_date %> domeenioksjonil .ee https://oksjon.internet.ee. Juhul kui domeenile <%= @domain.name %> ei tehta oksjonil 24h möödudes pakkumist, domeen vabaneb ja on registreerimiseks vabalt kättesaadav kõigile huvilistele. Muude võimalike oksjoni tulemuste kohta loe siit https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. +Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Registreeringu pikendamiseks pöörduge palun oma registripidaja poole. -Domeeni registreeringu pikendamiseks pöörduge palun oma registripidaja poole: +<%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt siit https://www.internet.ee/domeenid/domeenide-oksjonikeskkonna-kasutajatingimused#3-oksjonikeskkonna-enampakkumisel-osalemise-tingimused. + +Domeeni <%= @domain.name %> registripidaja: <%= render 'mailers/shared/registrar/registrar.et.text', registrar: @registrar %> Ülevaate kõikidest endaga seotud domeenidest saate registreerija portaalist https://registrant.internet.ee/registrant/. @@ -17,9 +19,11 @@ Domain <%= @domain.name %> has expired Dear registrant/administrative contact of .ee domain, -The domain name <%= @domain.name %> has expired and since <%= @domain.on_hold_date %> is no longer available on the Internet. The domain <%= @domain.name %> will be available for domain auction on <%= @domain.delete_date %> in the .ee auction portal at https://auction.internet.ee. If no offer is made for the domain <%= @domain.name %> at auction within 24 hours, the domain will be released and made freely available for registration to anyone interested on a first-come, first-served basis. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. +The domain name <%= @domain.name %> has expired and since <%= @domain.on_hold_date %> is no longer available on the Internet. To renew your domain registration, please contact your registrar. -To renew your domain registration, please contact your registrar: +If you do not renew the <%= @domain.name %> domain registration, it is deleted and put on auction to .ee domain auction environment at <%= @domain.delete_date %>. Read more about other potential auction results at https://www.internet.ee/domains/auction-environment-user-agreement#3-terms-and-conditions-for-participation-in-the-auction-of-the-auction-environment. + +Registrar of the <%= @domain.name %>: <%= render 'mailers/shared/registrar/registrar.en.text', registrar: @registrar %> You can find an overview of all your domains at the registrant's portal https://registrant.internet.ee/registrant/. @@ -32,11 +36,13 @@ You can find an overview of all your domains at the registrant's portal https:// Уважаемый регистрант/административный контакт домена .ee -Срок действия доменного имени <%= @domain.name %> истек, и с <%= @domain.on_hold_date %> оно больше не доступно в интернете. <%= @domain.delete_date %> домен <%= @domain.name %> будет представлен на доменном аукционе в аукционной среде .ee https://oksjon.internet.ee. Если в течение 24 часов в отношении домена <%= @domain.name %> не поступит предложений, домен освободится и станет доступным для всех желающих по принципу «кто раньше». О других возможных результатах аукциона читайте по ссылке https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. +Срок действия доменного имени <%= @domain.name %> истек, и с <%= @domain.on_hold_date %> оно больше не доступно в интернете. Для продления регистрации домена обратитесь пожалуйста к своему регистратору. -Для продления регистрации домена обратитесь, пожалуйста, к своему регистратору: +Если доменное имя не продлено, домен <%= @domain.name %> будет удален и <%= @domain.delete_date %> идет на аукцион в .ee среду аукциона. О других возможных результатах аукциона читайте здесь https://www.internet.ee/domeny/dogovor-pol-zovatelya-aukcionnoj-sredy#3-usloviya-uchastiya-v-aukcione. + +Pегистратор домена <%= @domain.name %>: <%= render 'mailers/shared/registrar/registrar.ru.text', registrar: @registrar %> Обзор всех связанных с вами доменов можете получить на портале регистратора https://registrant.internet.ee/registrant/ -<%= render 'mailers/shared/signatures/signature.ru.text' %> \ No newline at end of file +<%= render 'mailers/shared/signatures/signature.ru.text' %> diff --git a/app/views/registrant/contacts/show/_domains.html.erb b/app/views/registrant/contacts/show/_domains.html.erb index bb6d39fc0..d783b55b2 100644 --- a/app/views/registrant/contacts/show/_domains.html.erb +++ b/app/views/registrant/contacts/show/_domains.html.erb @@ -1,4 +1,5 @@ -<% domains = contact.all_domains(page: params[:domain_page], per: 20, params: params) %> +<% domains = contact.all_domains(page: params[:domain_page], per: 20, + params: domain_filter_params.to_h, requester: @requester_contact) %>
@@ -50,4 +51,4 @@ -
\ No newline at end of file +
diff --git a/app/views/registrar/contacts/partials/_domains.haml b/app/views/registrar/contacts/partials/_domains.haml index f409a6f24..cf721cb86 100644 --- a/app/views/registrar/contacts/partials/_domains.haml +++ b/app/views/registrar/contacts/partials/_domains.haml @@ -1,4 +1,5 @@ -- domains = contact.all_domains(page: params[:domain_page], per: 20, params: params) +- domains = contact.all_domains(page: params[:domain_page], per: 20, + params: domain_filter_params.to_h) .panel.panel-default .panel-heading .pull-left diff --git a/app/views/registrar/domains/_form.haml b/app/views/registrar/domains/_form.haml index d6428233b..690d0ee06 100644 --- a/app/views/registrar/domains/_form.haml +++ b/app/views/registrar/domains/_form.haml @@ -1,4 +1,5 @@ - path = (params[:domain_name]) ? update_registrar_domains_path : registrar_domains_path +- legaldoc_mandatory = params[:domain_name].blank? && current_registrar_user.legaldoc_mandatory? = form_tag(path, class: 'form-horizontal', multipart: true) do .row .col-md-8 @@ -14,7 +15,7 @@ .panel-body .form-group .col-md-3.control-label - - c, fr = 'required', true if params[:domain_name].blank? + - c, fr = 'required', true if legaldoc_mandatory = label_tag 'domain[legal_document]', t(:legal_document), class: c %p.help-block= t(:legal_document_max_size) .col-md-7 diff --git a/app/views/registrar/domains/_search_form.html.erb b/app/views/registrar/domains/_search_form.html.erb index 743f8de60..08b370b76 100644 --- a/app/views/registrar/domains/_search_form.html.erb +++ b/app/views/registrar/domains/_search_form.html.erb @@ -3,7 +3,7 @@
<%= f.label :name, for: nil %> - <%= f.search_field :name_matches, value: params[:q][:name_matches], class: 'form-control', + <%= f.search_field :name_matches, value: search_params[:name_matches], class: 'form-control', placeholder: t(:name) %>
@@ -44,7 +44,7 @@
<%= f.label :valid_to_from, for: nil %> - <%= f.search_field :valid_to_gteq, value: params[:q][:valid_to_gteq], + <%= f.search_field :valid_to_gteq, value: search_params[:valid_to_gteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_from) %>
@@ -53,7 +53,7 @@
<%= f.label :valid_to_until, for: nil %> - <%= f.search_field :valid_to_lteq, value: params[:q][:valid_to_lteq], + <%= f.search_field :valid_to_lteq, value: search_params[:valid_to_lteq], class: 'form-control js-datepicker', placeholder: t(:valid_to_until) %>
diff --git a/app/views/registrar/domains/delete.haml b/app/views/registrar/domains/delete.haml index ab1bdfa31..bea9ed118 100644 --- a/app/views/registrar/domains/delete.haml +++ b/app/views/registrar/domains/delete.haml @@ -10,14 +10,14 @@ .col-md-4.control-label = label_tag 'domain[verified]', t(:verified) .col-md-6 - = check_box_tag 'domain[verified]', '1', params[:verified].eql?('1'), onclick: "return (confirm('#{t(:verified_confirm)}') ? true : false);" + = check_box_tag 'domain[verified]', '1', params[:verified].eql?('1'), onclick: ("return (confirm('#{t(:verified_confirm)}') ? true : false);" if current_registrar_user.legaldoc_mandatory?) .form-group .col-md-4.control-label - = label_tag 'domain[legal_document]', t(:legal_document), class: 'required' + = label_tag 'domain[legal_document]', t(:legal_document) %p.help-block= t(:legal_document_max_size) .col-md-6 - = file_field_tag 'domain[legal_document]', required: true + = file_field_tag 'domain[legal_document]' = hidden_field_tag 'domain[name]', params[:domain_name] %hr .row diff --git a/app/views/registrar/domains/form/_general.haml b/app/views/registrar/domains/form/_general.haml index 0a729a262..5fa4d2a89 100644 --- a/app/views/registrar/domains/form/_general.haml +++ b/app/views/registrar/domains/form/_general.haml @@ -31,7 +31,7 @@ .col-md-7 = check_box_tag 'domain[verified]', '1', @domain_params[:verified].eql?('1'), onclick: "return (confirm('#{t(:verified_confirm)}') ? true : false);" - - unless params[:domain_name] + - if !params[:domain_name] || @dispute.present? .form-group .col-md-3.control-label = label_tag :domain_reserved_pw, t(:reserved_pw) diff --git a/app/views/registrar/domains/info.html.erb b/app/views/registrar/domains/info.html.erb index 1fcfc23c3..e88882233 100644 --- a/app/views/registrar/domains/info.html.erb +++ b/app/views/registrar/domains/info.html.erb @@ -6,6 +6,10 @@ class: 'btn btn-default') %> <%= link_to(t(:delete), delete_registrar_domains_path(domain_name: params[:domain_name]), class: 'btn btn-default') %> + <% if @client_holded %> + <%= link_to(t(:remove_client_hold), remove_hold_registrar_domains_path(domain_name: params[:domain_name]), + class: 'btn btn-default') %> + <% end %> <% else %> <%= link_to t('.transfer_btn'), new_registrar_domain_transfer_path(domain_name: params[:domain_name]), class: 'btn btn-default' %> diff --git a/app/views/registrar/invoices/partials/_banklinks.haml b/app/views/registrar/invoices/partials/_banklinks.haml index 84f6e1399..d9cbe1f21 100644 --- a/app/views/registrar/invoices/partials/_banklinks.haml +++ b/app/views/registrar/invoices/partials/_banklinks.haml @@ -3,5 +3,5 @@ - locals[:payment_channels].each do |meth| - meth = meth.strip - = link_to registrar_payment_with_path(meth, invoice_id: params[:id]) do + = link_to registrar_payment_with_path(meth, invoice_id: params[:id]), id: meth do = image_tag("#{meth}.png") diff --git a/app/views/registrar/invoices/partials/_payment_orders.haml b/app/views/registrar/invoices/partials/_payment_orders.haml new file mode 100644 index 000000000..d418ea1ac --- /dev/null +++ b/app/views/registrar/invoices/partials/_payment_orders.haml @@ -0,0 +1,19 @@ +%h4= "Payment Orders" +%hr +.table-responsive + %table.table.table-hover.table-condensed + %thead + %tr + %th{class: 'col-xs-1'}= "#" + %th{class: 'col-xs-1'}= "Channel" + %th{class: 'col-xs-2'}= "Status" + %th{class: 'col-xs-3'}= "Initiated" + %th{class: 'col-xs-4'}= "Notes" + %tbody + - @invoice.payment_orders.each do |payment_order| + %tr + %td= payment_order.id + %td= payment_order.channel + %td= payment_order.status + %td= payment_order.created_at + %td= payment_order.notes diff --git a/app/views/registrar/invoices/show.haml b/app/views/registrar/invoices/show.haml index 66a025eaf..5e6104091 100644 --- a/app/views/registrar/invoices/show.haml +++ b/app/views/registrar/invoices/show.haml @@ -17,4 +17,4 @@ - if @invoice.payable? .row.semifooter - .col-md-6-offset-6.text-right= render 'registrar/invoices/partials/banklinks', locals: { payment_channels: PaymentOrders::PAYMENT_METHODS } + .col-md-6-offset-6.text-right= render 'registrar/invoices/partials/banklinks', locals: { payment_channels: PaymentOrder::CUSTOMER_PAYMENT_METHODS } diff --git a/app/views/registrar/payments/pay.html.haml b/app/views/registrar/payments/pay.html.haml index 8e759f9ea..dd3fc982f 100644 --- a/app/views/registrar/payments/pay.html.haml +++ b/app/views/registrar/payments/pay.html.haml @@ -2,8 +2,8 @@ = t('registrar.invoices.redirected_to_intermediary') .payment-form - = form_tag @payment.form_url, method: :post do - - @payment.form_fields.each do |k, v| + = form_tag @payment_order.form_url, method: :post do + - @payment_order.form_fields.each do |k, v| = hidden_field_tag k, v = submit_tag t('registrar.invoices.go_to_intermediary') diff --git a/app/views/registrar/xml_consoles/epp_requests/domain/client_hold.xml b/app/views/registrar/xml_consoles/epp_requests/domain/client_hold.xml new file mode 100644 index 000000000..fcafec538 --- /dev/null +++ b/app/views/registrar/xml_consoles/epp_requests/domain/client_hold.xml @@ -0,0 +1,15 @@ + + + + + + example.ee + + + + + + timo-1579351654 + + diff --git a/app/views/registrar/xml_consoles/show.haml b/app/views/registrar/xml_consoles/show.haml index f96b67738..bb66116ee 100644 --- a/app/views/registrar/xml_consoles/show.haml +++ b/app/views/registrar/xml_consoles/show.haml @@ -29,6 +29,9 @@ , %a.js-load-xml{href: 'javascript:void(0)', data: {obj: 'domain', epp_action: 'delete'}} Delete + , + %a.js-load-xml{href: 'javascript:void(0)', data: {obj: 'domain', epp_action: 'client_hold'}} + Remove Client Hold %h4 Poll %a.js-load-xml{href: 'javascript:void(0)', data: {obj: 'poll', epp_action: 'poll'}} diff --git a/bin/bundle b/bin/bundle index 66e9889e8..8bfc37be6 100755 --- a/bin/bundle +++ b/bin/bundle @@ -1,3 +1,3 @@ #!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __dir__) load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails index 5191e6927..073966023 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/bin/setup b/bin/setup index fdf4596e7..ab3c84d9b 100755 --- a/bin/setup +++ b/bin/setup @@ -1,33 +1,38 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require 'pathname' -require 'fileutils' +include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) - +APP_ROOT = Pathname.new File.expand_path('../../', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -Dir.chdir APP_ROOT do +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. - puts '== Installing dependencies with bundler ==' + puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - puts "\n== Copying sample development database config files ==" + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + puts "\n== Copying sample files ==" unless File.exist?('config/database.yml') - system! 'cp config/database-example-development.yml config/database.yml' + system! 'cp config/database.yml.sample config/database.yml' end puts "\n== Preparing database ==" - system! 'bin/rake db:setup' + system! 'bin/rails db:setup' puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rake log:clear tmp:clear' + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! 'touch tmp/restart.txt' - + system! 'bin/rails restart' end diff --git a/bin/update b/bin/update new file mode 100755 index 000000000..a8e4462f2 --- /dev/null +++ b/bin/update @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/yarn b/bin/yarn new file mode 100755 index 000000000..adabdd976 --- /dev/null +++ b/bin/yarn @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + exec 'yarnpkg', *ARGV +rescue Errno::ENOENT + $stderr.puts 'Yarn executable was not detected in the system.' + $stderr.puts 'Download Yarn at https://yarnpkg.com/en/docs/install' + exit 1 +end diff --git a/config.ru b/config.ru index 4fa72a37f..ec46ca9f1 100644 --- a/config.ru +++ b/config.ru @@ -1,6 +1,6 @@ # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require_relative 'config/environment' run Rails.application # turn automatic que temp off diff --git a/config/app.yml b/config/app.yml index 763da3373..87f99f4ad 100644 --- a/config/app.yml +++ b/config/app.yml @@ -6,6 +6,7 @@ defaults: &defaults tech_contacts_max_count: 10 orphans_contacts_in_months: 6 expire_pending_confirmation: 48 + legal_document_is_mandatory: true ds_digest_type: 2 ds_data_allowed: false @@ -44,6 +45,8 @@ defaults: &defaults registrar_ip_whitelist_enabled: false api_ip_whitelist_enabled: false + dispute_period_in_months: 36 + registry_juridical_name: "Eesti Interneti SA" registry_reg_no: "90010019" registry_email: "info@internet.ee" diff --git a/config/application.rb b/config/application.rb index d02c6e9d0..5f4481512 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,15 +1,8 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' -# Pick the frameworks you want: -require 'active_model/railtie' -require 'active_record/railtie' -require 'action_controller/railtie' -require 'action_mailer/railtie' -require 'action_view/railtie' -require 'sprockets/railtie' -require 'csv' require 'rails/all' -# require "rails/test_unit/railtie" +require 'English' +require 'csv' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -23,6 +16,9 @@ end module DomainNameRegistry class Application < Rails::Application + config.load_defaults 6.0 + config.autoloader = :classic # Do not use zeitwerk for now + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. @@ -43,21 +39,6 @@ module DomainNameRegistry config.eager_load_paths << config.root.join('lib', 'validators') config.watchable_dirs['lib'] = %i[rb] - # Add the fonts path - config.assets.paths << Rails.root.join('vendor', 'assets', 'fonts') - - # Precompile additional assets - config.assets.precompile += %w(*.svg *.eot *.woff *.ttf) - config.assets.precompile += %w(admin-manifest.css admin-manifest.js) - config.assets.precompile += %w(registrar-manifest.css registrar-manifest.js) - config.assets.precompile += %w(registrant-manifest.css registrant-manifest.js) - - # Active Record used to suppresses errors raised within - # `after_rollback`/`after_commit` callbacks and only printed them to the logs. - # In the next version, these errors will no longer be suppressed. - # Instead, the errors will propagate normally just like in other Active Record callbacks. - config.active_record.raise_in_transactional_callbacks = true - config.active_record.schema_format = :sql config.generators do |g| @@ -93,5 +74,13 @@ module DomainNameRegistry config.action_view.default_form_builder = 'DefaultFormBuilder' config.secret_key_base = Figaro.env.secret_key_base + + # Using `Rails.application.config.active_record.belongs_to_required_by_default` in + # `new_framework_defaults.rb` has no effect in Rails 5.0.x. + # https://github.com/rails/rails/issues/23589 + # https://stackoverflow.com/questions/38850712/rails-5-belongs-to-required-by-default-doesnt-work + # Not supported by `paper_trail` gem < 5.0 + # https://github.com/paper-trail-gem/paper_trail/issues/682 + config.active_record.belongs_to_required_by_default = false end -end \ No newline at end of file +end diff --git a/config/application.yml.sample b/config/application.yml.sample index 691740b2a..2cd19b768 100644 --- a/config/application.yml.sample +++ b/config/application.yml.sample @@ -148,9 +148,8 @@ action_mailer_default_port: # default: no port (80) action_mailer_default_from: # no-reply@example.com action_mailer_force_delete_from: # `From` header for `DomainDeleteMailer#forced` email -lhv_keystore: +lhv_p12_keystore: lhv_keystore_password: -lhv_keystore_alias: lhv_ca_file: # Needed only in dev mode lhv_dev_mode: 'false' @@ -163,9 +162,9 @@ test: action_mailer_default_host: 'registry.test' action_mailer_default_from: 'no-reply@registry.test' action_mailer_force_delete_from: 'legal@registry.test' - lhv_keystore: 'test/fixtures/files/keystore.jks' + lhv_p12_keystore: 'test/fixtures/files/keystore.p12' lhv_keystore_password: 'testtest' - lhv_keystore_alias: 'testtest' + legal_documents_dir: 'test/fixtures/files' # Airbrake // Errbit: airbrake_host: "https://your-errbit-host.ee" diff --git a/config/boot.rb b/config/boot.rb index 5e5f0c1fa..da8896b7b 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,4 @@ -# Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' # Set up gems listed in the Gemfile. +require 'bootsnap/setup' diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 000000000..858bb1f14 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 + channel_prefix: domain_name_registry_production diff --git a/config/environment.rb b/config/environment.rb index ee8d90dc6..426333bb4 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require File.expand_path('../application', __FILE__) +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/config/environments/development.rb.sample b/config/environments/development.rb.sample index f5ed70e06..377f2cbbd 100644 --- a/config/environments/development.rb.sample +++ b/config/environments/development.rb.sample @@ -9,29 +9,59 @@ Rails.application.configure do # Do not eager load code on boot. config.eager_load = false - # Show full error reports and disable caching. + # Show full error reports. config.consider_all_requests_local = true - config.action_controller.perform_caching = false + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join('tmp', 'caching-dev.txt').exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - config.logger = ActiveSupport::Logger.new(nil) - # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. - config.assets.debug = false + config.assets.debug = true - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true + # Suppress logger output for asset requests. + config.assets.quiet = true - config.action_view.raise_on_missing_translations = true + # Allow any host to access development + config.hosts.clear + + # Raises error for missing translations. + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker end # In this mode, any jobs you queue will be run in the same thread, synchronously diff --git a/config/environments/production.rb b/config/environments/production.rb index 11a620e35..6e13ea1f7 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -19,8 +19,7 @@ Rails.application.configure do # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. # config.action_dispatch.rack_cache = true - # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_files = false + config.public_file_server.enabled = false # Compress JavaScripts and CSS. config.assets.js_compressor = Uglifier.new(harmony: true) @@ -29,38 +28,37 @@ Rails.application.configure do # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs. - config.assets.digest = true + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Mount Action Cable outside main process or domain + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Set to :debug to see everything in the log. - config.log_level = :info + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug # Prepend all log lines with the following tags. - config.log_tags = [:subdomain, :uuid, :remote_ip] - - # Use a different logger for distributed setups. - require 'syslog/logger' - config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new(ENV['app_name'] || 'registry')) + config.log_tags = [:request_id, :subdomain, :remote_ip] # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) + # Use a real queuing backend for Active Job (and separate queues per environment) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "domain_name_registry_#{Rails.env}" + config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -71,19 +69,26 @@ Rails.application.configure do config.i18n.fallbacks = true # Send deprecation notices to registered listeners. - config.active_support.deprecation = :log - - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false + config.active_support.deprecation = :notify # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new + # Use a different logger for distributed setups. + require 'syslog/logger' + config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new(ENV['app_name'] || 'registry')) + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false end -# In off mode, queueing a job will simply insert it into the database - -# the current process will make no effort to run it. +# In off mode, queueing a job will simply insert it into the database - +# the current process will make no effort to run it. # You should use this if you want to use a dedicated process to work tasks -Que.mode = :off +Que.mode = :off diff --git a/config/environments/test.rb b/config/environments/test.rb index 119f6d815..c55e59e31 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,24 +1,40 @@ + Rails.application.configure do + # $VERBOSE = nil # Settings specified here will take precedence over those in config/application.rb. + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! config.cache_classes = true - config.eager_load = false - config.serve_static_files = true - config.static_cache_control = 'public, max-age=3600' + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false config.consider_all_requests_local = true config.action_controller.perform_caching = false + # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false + # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - config.active_support.test_order = :random - config.active_support.deprecation = :stderr - config.logger = ActiveSupport::Logger.new(nil) + config.action_mailer.raise_delivery_errors = false + # Print deprecation notices to the stderr. + config.active_support.deprecation = :silence + + # Raises error for missing translations config.action_view.raise_on_missing_translations = true # If set to :null_store, Setting.x returns nil after first spec runs (database is emptied) diff --git a/config/initializers/airbrake.rb b/config/initializers/airbrake.rb index 917deb02a..abfe408c1 100644 --- a/config/initializers/airbrake.rb +++ b/config/initializers/airbrake.rb @@ -3,6 +3,9 @@ Airbrake.configure do |config| config.project_id = ENV['airbrake_project_id'] config.project_key = ENV['airbrake_project_key'] config.root_directory = Rails.root + config.job_stats = false + config.query_stats = false + config.performance_stats = false config.logger = if ENV['RAILS_LOG_TO_STDOUT'].present? Logger.new(STDOUT, level: Rails.logger.level) @@ -14,5 +17,5 @@ Airbrake.configure do |config| end config.environment = ENV['airbrake_env'] || Rails.env config.ignore_environments = %w[test] - config.blacklist_keys = Rails.application.config.filter_parameters + config.blocklist_keys = Rails.application.config.filter_parameters end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 000000000..89d2efab2 --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index d1a94d7c6..d5a05217a 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -1 +1,12 @@ -Rails.application.config.assets.precompile += %w( login.css registrar-manifest.css shared/pdf.css ) +# Be sure to restart your server when you modify this file. + +Rails.application.configure do + # Version of your assets, change this if you want to expire all your assets. + config.assets.version = '1.0' + + # Add additional assets to the asset load path + config.assets.paths << Rails.root.join('vendor', 'assets', 'fonts', 'node_modules') + + # Precompile additional assets. + # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +end diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 000000000..d3bcaa5ec --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index 7f70458de..5a6a32d37 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -1,3 +1,5 @@ # Be sure to restart your server when you modify this file. +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/current_commit_hash.rb b/config/initializers/current_commit_hash.rb deleted file mode 100644 index b018b46fd..000000000 --- a/config/initializers/current_commit_hash.rb +++ /dev/null @@ -1 +0,0 @@ -CURRENT_COMMIT_HASH = `git rev-parse --short HEAD` diff --git a/config/initializers/money.rb b/config/initializers/money.rb index cb476b589..a52ff280d 100644 --- a/config/initializers/money.rb +++ b/config/initializers/money.rb @@ -1,4 +1,6 @@ MoneyRails.configure do |config| # Wrapper for Money#default_currency with additional functionality config.default_currency = :eur -end \ No newline at end of file + config.rounding_mode = BigDecimal::ROUND_HALF_EVEN + config.locale_backend = :i18n +end diff --git a/config/initializers/new_framework_defaults.rb b/config/initializers/new_framework_defaults.rb new file mode 100644 index 000000000..2f9c3c5cb --- /dev/null +++ b/config/initializers/new_framework_defaults.rb @@ -0,0 +1,28 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.0 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# DEPRECATION WARNING: raise_on_unfiltered_parameters is deprecated and has no effect in Rails 5.1. +#Rails.application.config.action_controller.raise_on_unfiltered_parameters = true + +# Enable per-form CSRF tokens. Previous versions had false. +Rails.application.config.action_controller.per_form_csrf_tokens = true + +# Enable origin-checking CSRF mitigation. Previous versions had false. +Rails.application.config.action_controller.forgery_protection_origin_check = true + +# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. +# Previous versions had false. +ActiveSupport.to_time_preserves_timezone = true + +# Do not halt callback chains when a callback returns false. Previous versions had true. +# DEPRECATION WARNING: ActiveSupport.halt_callback_chains_on_return_false= is deprecated and +# will be removed in Rails 5.2. +#ActiveSupport.halt_callback_chains_on_return_false = false + +# Configure SSL options to enable HSTS with subdomains. Previous versions had false. +Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/config/initializers/new_framework_defaults_5_1.rb b/config/initializers/new_framework_defaults_5_1.rb new file mode 100644 index 000000000..9010abd5c --- /dev/null +++ b/config/initializers/new_framework_defaults_5_1.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.1 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Make `form_with` generate non-remote forms. +Rails.application.config.action_view.form_with_generates_remote_forms = false + +# Unknown asset fallback will return the path passed in when the given +# asset is not present in the asset pipeline. +# Rails.application.config.assets.unknown_asset_fallback = false diff --git a/config/initializers/new_framework_defaults_5_2.rb b/config/initializers/new_framework_defaults_5_2.rb new file mode 100644 index 000000000..c383d072b --- /dev/null +++ b/config/initializers/new_framework_defaults_5_2.rb @@ -0,0 +1,38 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.2 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Make Active Record use stable #cache_key alongside new #cache_version method. +# This is needed for recyclable cache keys. +# Rails.application.config.active_record.cache_versioning = true + +# Use AES-256-GCM authenticated encryption for encrypted cookies. +# Also, embed cookie expiry in signed or encrypted cookies for increased security. +# +# This option is not backwards compatible with earlier Rails versions. +# It's best enabled when your entire app is migrated and stable on 5.2. +# +# Existing cookies will be converted on read then written with the new scheme. +# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true + +# Use AES-256-GCM authenticated encryption as default cipher for encrypting messages +# instead of AES-256-CBC, when use_authenticated_message_encryption is set to true. +# Rails.application.config.active_support.use_authenticated_message_encryption = true + +# Add default protection from forgery to ActionController::Base instead of in +# ApplicationController. +# Rails.application.config.action_controller.default_protect_from_forgery = true + +# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and +# 'f' after migrating old data. +# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true + +# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header. +# Rails.application.config.active_support.use_sha1_digests = true + +# Make `form_with` generate id attributes for any generated HTML tags. +# Rails.application.config.action_view.form_with_generates_ids = true diff --git a/config/initializers/new_framework_defaults_6_0.rb b/config/initializers/new_framework_defaults_6_0.rb new file mode 100644 index 000000000..998b2f346 --- /dev/null +++ b/config/initializers/new_framework_defaults_6_0.rb @@ -0,0 +1,45 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 6.0 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Don't force requests from old versions of IE to be UTF-8 encoded. +Rails.application.config.action_view.default_enforce_utf8 = false + +# Embed purpose and expiry metadata inside signed and encrypted +# cookies for increased security. +# +# This option is not backwards compatible with earlier Rails versions. +# It's best enabled when your entire app is migrated and stable on 6.0. +# Rails.application.config.action_dispatch.use_cookies_with_metadata = true + +# Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. +Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false + +# Return false instead of self when enqueuing is aborted from a callback. +Rails.application.config.active_job.return_false_on_aborted_enqueue = true + +# Send Active Storage analysis and purge jobs to dedicated queues. +# Rails.application.config.active_storage.queues.analysis = :active_storage_analysis +# Rails.application.config.active_storage.queues.purge = :active_storage_purge + +# When assigning to a collection of attachments declared via `has_many_attached`, replace existing +# attachments instead of appending. Use #attach to add new attachments without replacing existing ones. +# Rails.application.config.active_storage.replace_on_assign_to_many = true + +# Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. +# +# The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), +# will be removed in Rails 6.1. This setting is not backwards compatible with earlier Rails versions. +# If you send mail in the background, job workers need to have a copy of +# MailDeliveryJob to ensure all delivery jobs are processed properly. +# Make sure your entire app is migrated and stable on 6.0 before using this setting. +# Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" + +# Enable the same cache key to be reused when the object being cached of type +# `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) +# of the relation's cache key into the cache version to support recycling cache key. +Rails.application.config.active_record.collection_cache_versioning = false diff --git a/config/initializers/que.rb b/config/initializers/que.rb new file mode 100644 index 000000000..560b1ec1e --- /dev/null +++ b/config/initializers/que.rb @@ -0,0 +1,7 @@ +Que::Adapters::Base::CAST_PROCS[1184] = lambda do |value| + case value + when Time then value + when String then Time.parse(value) + else raise "Unexpected time class: #{value.class} (#{value.inspect})" + end +end diff --git a/config/initializers/truemail.rb b/config/initializers/truemail.rb new file mode 100644 index 000000000..f4517fbc0 --- /dev/null +++ b/config/initializers/truemail.rb @@ -0,0 +1,77 @@ +require 'truemail' + +Truemail.configure do |config| + # Required parameter. Must be an existing email on behalf of which verification will be performed + config.verifier_email = ENV['action_mailer_default_from'] + + # Optional parameter. Must be an existing domain on behalf of which verification will be performed. + # By default verifier domain based on verifier email + # config.verifier_domain = 'internet.ee' + + # Optional parameter. You can override default regex pattern + # config.email_pattern = /regex_pattern/ + + # Optional parameter. You can override default regex pattern + # config.smtp_error_body_pattern = /regex_pattern/ + + # Optional parameter. Connection timeout is equal to 2 ms by default. + # config.connection_timeout = 1 + + # Optional parameter. A SMTP server response timeout is equal to 2 ms by default. + # config.response_timeout = 1 + + # Optional parameter. Total of connection attempts. It is equal to 2 by default. + # This parameter uses in mx lookup timeout error and smtp request (for cases when + # there is one mx server). + config.connection_attempts = 3 + + # Optional parameter. You can predefine default validation type for + # Truemail.validate('email@email.com') call without with-parameter + # Available validation types: :regex, :mx, :smtp + if Rails.env.production? + config.default_validation_type = :mx + else + config.default_validation_type = :regex + end + + # Optional parameter. You can predefine which type of validation will be used for domains. + # Also you can skip validation by domain. Available validation types: :regex, :mx, :smtp + # This configuration will be used over current or default validation type parameter + # All of validations for 'somedomain.com' will be processed with regex validation only. + # And all of validations for 'otherdomain.com' will be processed with mx validation only. + # It is equal to empty hash by default. + # config.validation_type_for = { 'somedomain.com' => :regex, 'otherdomain.com' => :mx } + + # Optional parameter. Validation of email which contains whitelisted domain always will + # return true. Other validations will not processed even if it was defined in validation_type_for + # It is equal to empty array by default. + # config.whitelisted_domains = [] + + # Optional parameter. With this option Truemail will validate email which contains whitelisted + # domain only, i.e. if domain whitelisted, validation will passed to Regex, MX or SMTP validators. + # Validation of email which not contains whitelisted domain always will return false. + # It is equal false by default. + #config.whitelist_validation = true + + # Optional parameter. Validation of email which contains blacklisted domain always will + # return false. Other validations will not processed even if it was defined in validation_type_for + # It is equal to empty array by default. + #config.blacklisted_domains = [] + + # Optional parameter. This option will provide to use not RFC MX lookup flow. + # It means that MX and Null MX records will be cheked on the DNS validation layer only. + # By default this option is disabled. + # config.not_rfc_mx_lookup_flow = true + + # Optional parameter. This option will be parse bodies of SMTP errors. It will be helpful + # if SMTP server does not return an exact answer that the email does not exist + # By default this option is disabled, available for SMTP validation only. + # config.smtp_safe_check = true + + # Optional parameter. This option will enable tracking events. You can print tracking events to + # stdout, write to file or both of these. Tracking event by default is :error + # Available tracking event: :all, :unrecognized_error, :recognized_error, :error + unless Rails.env.test? + config.logger = { tracking_event: :all, stdout: true, log_absolute_path: Rails.root.join('log', 'truemail.log').to_s } + end +end diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 33725e95f..bbfc3961b 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -5,10 +5,10 @@ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do - wrap_parameters format: [:json] if respond_to?(:wrap_parameters) + wrap_parameters format: [:json] end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do -# self.include_root_in_json = true +# self.include_root_in_json = true # end diff --git a/config/locales/admin/api_users.en.yml b/config/locales/admin/api_users.en.yml index 89a31f081..9fde2db14 100644 --- a/config/locales/admin/api_users.en.yml +++ b/config/locales/admin/api_users.en.yml @@ -2,16 +2,34 @@ en: admin: api_users: index: - new_btn: New API user - title: API users - active: Active - - show: - active: Active - subject: Subject + header: API users new: - title: New API user + header: New API user + + create: + created: API user has been successfully created + + show: + edit_btn: Edit + delete_btn: Delete + delete_btn_confirm: Are you sure you want to delete this API user? + + details: + header: Details + + certificates: + subject: Subject + + edit: + header: Edit API user + + update: + updated: API user has been successfully updated + + destroy: + deleted: API user has been successfully deleted form: - active: Active + create_btn: Create API user + update_btn: Update API user diff --git a/config/locales/admin/disputes.en.yml b/config/locales/admin/disputes.en.yml new file mode 100644 index 000000000..9632dde4a --- /dev/null +++ b/config/locales/admin/disputes.en.yml @@ -0,0 +1,19 @@ +en: + activerecord: + errors: + models: + dispute: + attributes: + starts_at: + future: 'can not be greater than today' + admin: + disputes: + index: + title: Disputed domains + new_btn: New disputed domain + reset_btn: Reset + + form: + password_hint: Generated automatically if left blank + optional: Not required by default + past_or_today: Can not be greater than today's date diff --git a/config/locales/admin/domains.en.yml b/config/locales/admin/domains.en.yml index 2abdaee91..c6e96bb15 100644 --- a/config/locales/admin/domains.en.yml +++ b/config/locales/admin/domains.en.yml @@ -31,6 +31,7 @@ en: force_delete_dialog: title: Force delete notify_by_email: Notify registrant and administrative contacts by email + use_soft_delete: Use soft delete procedure email_template: Email template close_btn: Close dialog submit_btn: Force delete domain diff --git a/config/locales/admin/email_verifable.en.yml b/config/locales/admin/email_verifable.en.yml new file mode 100644 index 000000000..724fa4c32 --- /dev/null +++ b/config/locales/admin/email_verifable.en.yml @@ -0,0 +1,5 @@ +en: + email_verifable: + email_smtp_check_error: SMTP check error + email_mx_check_error: Mail domain not found + email_regex_check_error: Invalid format diff --git a/config/locales/admin/email_verifable.et.yml b/config/locales/admin/email_verifable.et.yml new file mode 100644 index 000000000..6c008ed11 --- /dev/null +++ b/config/locales/admin/email_verifable.et.yml @@ -0,0 +1,5 @@ +et: + email_verifable: + email_smtp_check_error: Eposti aadressi ei leitud (SMTP viga) + email_mx_check_error: Eposti aadressi domeeni ei leitud + email_regex_check_error: Eposti aadress on vigane diff --git a/config/locales/admin/legal_documents.en.yml b/config/locales/admin/legal_documents.en.yml new file mode 100644 index 000000000..f24d883a6 --- /dev/null +++ b/config/locales/admin/legal_documents.en.yml @@ -0,0 +1,2 @@ +en: + legal_doc_not_found: "There is an error downloading legal document: file not found" diff --git a/config/locales/admin/legal_documents.et.yml b/config/locales/admin/legal_documents.et.yml new file mode 100644 index 000000000..d3ebfa512 --- /dev/null +++ b/config/locales/admin/legal_documents.et.yml @@ -0,0 +1,2 @@ +et: + legal_doc_not_found: "Viga juriidilise dokumendi allalaadimisel: faili ei leitud" diff --git a/config/locales/admin/menu.en.yml b/config/locales/admin/menu.en.yml index 2c31a5193..617341c6a 100644 --- a/config/locales/admin/menu.en.yml +++ b/config/locales/admin/menu.en.yml @@ -13,6 +13,7 @@ en: zones: Zones blocked_domains: Blocked domains reserved_domains: Reserved domains + disputed_domains: Disputed domains epp_log: EPP log repp_log: REPP log que: Que diff --git a/config/locales/admin/registrars.en.yml b/config/locales/admin/registrars.en.yml index b6ba75fc9..59a999bd2 100644 --- a/config/locales/admin/registrars.en.yml +++ b/config/locales/admin/registrars.en.yml @@ -25,7 +25,7 @@ en: preferences: header: Preferences - users: + api_users: header: API Users new_btn: New API user @@ -49,6 +49,8 @@ en: misc: Miscellaneous create_btn: Create registrar update_btn: Update registrar + legaldoc_optout: Opt-out from legal document requirement + legaldoc_optout_comment: Commentary on opt-out address: header: Address @@ -67,4 +69,4 @@ en: iban_hint: Used for e-invoices preferences: - header: Preferences \ No newline at end of file + header: Preferences diff --git a/config/locales/api_users.en.yml b/config/locales/api_users.en.yml index 757ded049..9d4fcb63a 100644 --- a/config/locales/api_users.en.yml +++ b/config/locales/api_users.en.yml @@ -3,14 +3,4 @@ en: attributes: api_user: plain_text_password: Password - errors: - models: - api_user: - attributes: - username: - blank: 'Username is missing' - taken: 'Username already exists' - plain_text_password: - blank: 'Password is missing' - registrar: - blank: 'Registrar is missing' \ No newline at end of file + roles: Role diff --git a/config/locales/contacts.en.yml b/config/locales/contacts.en.yml index cdfe2277d..906bde193 100644 --- a/config/locales/contacts.en.yml +++ b/config/locales/contacts.en.yml @@ -20,6 +20,9 @@ en: email: blank: "Required parameter missing - email" invalid: "Email is invalid" + email_smtp_check_error: SMTP check error + email_mx_check_error: Mail domain not found + email_regex_check_error: Invalid format domains: exist: 'Object association prohibits operation' statuses: diff --git a/config/locales/en.yml b/config/locales/en.yml index 5742398f7..27299072e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -24,6 +24,8 @@ en: key_data_not_allowed: 'keyData object is not allowed' required_parameter_missing_reserved: 'Required parameter missing; reserved>pw element required for reserved domains' invalid_auth_information_reserved: 'Invalid authorization information; invalid reserved>pw value' + required_parameter_missing_disputed: 'Required parameter missing; disputed pw element required for dispute domains' + invalid_auth_information_disputed: 'Invalid authorization information; invalid disputed>pw value' domain_name_blocked: 'Data management policy violation: Domain name is blocked [name]' name_dirty: invalid: 'Domain name is invalid' @@ -195,7 +197,6 @@ en: domain_details: 'Domain details' registered_at: 'Registered at' password: 'Password' - authinfo_pw: 'AuthInfo pw' valid_from: 'Valid from' general: 'General' contacts: 'Contacts' @@ -207,6 +208,7 @@ en: statuses: 'Statuses' description: 'Description' delete: 'Delete' + remove_client_hold: 'Remove clientHold' are_you_sure: 'Are you sure?' back: 'Back' new_domain: 'New domain' @@ -277,7 +279,6 @@ en: certificate_signing_req: 'Certificate signing request' csr: 'CSR' crt: 'CRT' - back_to_api_user: 'Back to API user' dnskey: 'DNS key' dnskeys: 'DNS Keys' @@ -582,6 +583,7 @@ en: tech: Tech contact valid: Valid object_is_not_eligible_for_renewal: 'Object is not eligible for renewal' + object_is_not_holded: 'Object is not holded' bank_statement_desc: 'Import file row will match only when matching following attributes:
ref number
payment amount
invoice number (the first numerical value in comment field)
.' create_bank_statement: 'Create bank statement' create_bank_transaction: 'Create bank transaction' @@ -620,16 +622,21 @@ en: created_at_from: 'Created at from' created_at_until: 'Created at until' is_registrant: 'Is registrant' - force_delete_set_on_domain: 'Force delete set on domain %{domain_name}' + force_delete_set_on_domain: 'Force delete set on domain %{domain_name}. Outzone date: %{outzone_date}. Purge date: %{purge_date}' + grace_period_started_domain: 'For domain %{domain_name} started 45-days redemption grace period, ForceDelete will be in effect from %{date}' + force_delete_cancelled: 'Force delete is cancelled on domain %{domain_name}' contact_is_not_valid: 'Contact %{value} is not valid, please fix the invalid contact' next: 'Next' previous: 'Previous' available_verification_url_not_found: 'Available verification url not found, for domain.' add_reserved_domain: 'Add domain to reserved list' add_blocked_domain: 'Add domain to blocked list' + add_disputed_domain: 'Add domain to disputed list' edit_pw: 'Edit Pw' + edit_dispute: 'Edit dispute' optional: 'Optional' test_registrar: "Test registrar" + emails: 'Email addresses' verified_confirm: 'Verified status is for cases when current registrant is the one applying for the update. Legal document signed by the registrant is required. Are you sure this update is properly verified with the registrant?' verified: 'Verified' deleted: 'Deleted' diff --git a/config/locales/et.yml b/config/locales/et.yml index 05d32be24..9cb8aaa4a 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -5,3 +5,4 @@ et: date: # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, Jaanuar, Veebruar, Märts, Aprill, Mai, Juuni, Juuli, August, September, Oktoober, November, Detsember] + emails: "Meillaadressid" diff --git a/config/locales/registrar/payments.en.yml b/config/locales/registrar/payments.en.yml new file mode 100644 index 000000000..9c817e0ea --- /dev/null +++ b/config/locales/registrar/payments.en.yml @@ -0,0 +1,7 @@ +en: + registrar: + payments: + back: + payment_successful: 'Thank you! Payment received successfully.' + successful_payment_backend_error: 'We received your payment, but something went wrong on our side. Please contact us via email or phone.' + payment_not_received: 'Payment was unsuccessful. Please make sure you have enough funds on your account and try again.' diff --git a/config/locales/registrars.en.yml b/config/locales/registrars.en.yml index 609f9f94a..c57f2e891 100644 --- a/config/locales/registrars.en.yml +++ b/config/locales/registrars.en.yml @@ -1,4 +1,8 @@ en: + registrar: + invoice_yearly_product_description: '%{tld} registration: %{length} year(s)' + invoice_monthly_product_description: '%{tld} registration: %{length} month(s)' + monthly_summary_title: 'Domain registrations - %{date}' activerecord: errors: models: @@ -8,4 +12,4 @@ en: forbidden: is forbidden vat_rate: present: >- - must be blank when a registrar is VAT-registered in the same country as registry \ No newline at end of file + must be blank when a registrar is VAT-registered in the same country as registry diff --git a/config/locales/registrars.et.yml b/config/locales/registrars.et.yml new file mode 100644 index 000000000..1001638c1 --- /dev/null +++ b/config/locales/registrars.et.yml @@ -0,0 +1,5 @@ +et: + registrar: + invoice_yearly_product_description: '%{tld} registreerimine: %{length} aasta(t)' + invoice_monthly_product_description: '%{tld} registreerimine: %{length} kuu(d)' + monthly_summary_title: 'Domeenide registreerimine - %{date}' diff --git a/config/routes.rb b/config/routes.rb index 1e9a6bfc4..1c03129db 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -39,6 +39,19 @@ Rails.application.routes.draw do mount Repp::API => '/' + namespace :repp do + namespace :v1 do + resources :auctions, only: %i[index] + resources :retained_domains, only: %i[index] + end + end + + match 'repp/v1/*all', + controller: 'api/cors', + action: 'cors_preflight_check', + via: [:options], + as: 'repp_cors_preflight_check' + namespace :api do namespace :v1 do namespace :registrant do @@ -99,6 +112,7 @@ Rails.application.routes.draw do get 'check' get 'delete' get 'search_contacts' + get 'remove_hold' end end resources :domain_transfers, only: %i[new create] @@ -127,11 +141,11 @@ Rails.application.routes.draw do end end - get 'pay/return/:bank' => 'payments#back', as: 'return_payment_with' - post 'pay/return/:bank' => 'payments#back' - put 'pay/return/:bank' => 'payments#back' - post 'pay/callback/:bank' => 'payments#callback', as: 'response_payment_with' - get 'pay/go/:bank' => 'payments#pay', as: 'payment_with' + get 'pay/return/:payment_order' => 'payments#back', as: 'return_payment_with' + post 'pay/return/:payment_order' => 'payments#back' + put 'pay/return/:payment_order' => 'payments#back' + post 'pay/callback/:payment_order' => 'payments#callback', as: 'response_payment_with' + get 'pay/go/:bank' => 'payments#pay', as: 'payment_with' namespace :settings do resource :balance_auto_reload, controller: :balance_auto_reload, only: %i[edit update destroy] @@ -257,9 +271,14 @@ Rails.application.routes.draw do get 'delete' end end + resources :disputes do + member do + get 'delete' + end + end resources :registrars do - resources :api_users + resources :api_users, except: %i[index] resources :white_ips end @@ -270,7 +289,8 @@ Rails.application.routes.draw do end resources :admin_users - resources :api_users do + # /admin/api_users is mainly for manual testing + resources :api_users, only: [:index, :show] do resources :certificates do member do post 'sign' diff --git a/config/schedule.rb b/config/schedule.rb index fe920dc6d..7ebf97d12 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -46,6 +46,10 @@ if @cron_group == 'registry' runner 'DomainCron.start_redemption_grace_period' end + every 1.day do + runner 'DomainCron.start_client_hold' + end + every '0 0 1 * *' do runner 'Directo.send_monthly_invoices' end @@ -58,6 +62,10 @@ if @cron_group == 'registry' rake 'domain:discard' end + every 10.minutes do + rake 'verify_email:all_domains' + end + # Should be at least once every 4 days, since according to LHV specs: # "Unread messages older than 5 days are automatically scheduled for deletion" # https://partners.lhv.ee/en/connect/#messaging diff --git a/config/secrets.yml b/config/secrets.yml new file mode 100644 index 000000000..5a3114b22 --- /dev/null +++ b/config/secrets.yml @@ -0,0 +1,22 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rails secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +development: + secret_key_base: d876b4cf172fe17628b4486b302e1d805109f4dfbf25aa8f2d89e6cf821dfdc94f4c753e4fdbaa0b6647ba687058266661632b2cd3975c41fb21dbc588b38c92 + +test: + secret_key_base: 69ecc590b3de231130e3fb390df48a4eb9259722754ef5df6a9e9ab78d69149d8c16ec2d79791c5ba7a89ad7c5afaa8cec1aa794e9a6f986d3c7319a08d6bce2 + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 000000000..c9119b40c --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,6 @@ +%w( + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +).each { |path| Spring.watch(path) } diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 000000000..d32f76e8f --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/data/20150601083516_add_cert_common_name.rb b/db/data/20150601083516_add_cert_common_name.rb index ef401b871..d0959e5b7 100644 --- a/db/data/20150601083516_add_cert_common_name.rb +++ b/db/data/20150601083516_add_cert_common_name.rb @@ -1,16 +1,15 @@ -class AddCertCommonName < ActiveRecord::Migration +class AddCertCommonName < ActiveRecord::Migration[5.1] def self.up - Certificate.all.each do |x| - if x.crt.blank? && x.csr.present? - pc = x.parsed_csr.try(:subject).try(:to_s) || '' - cn = pc.scan(/\/CN=(.+)/).flatten.first - x.common_name = cn.split('/').first - end - x.save - end + # Certificate.all.each do |x| + # if x.crt.blank? && x.csr.present? + # pc = x.parsed_csr.try(:subject).try(:to_s) || '' + # cn = pc.scan(/\/CN=(.+)/).flatten.first + # x.common_name = cn.split('/').first + # end + # x.save + # end end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20150601083800_add_cert_md5.rb b/db/data/20150601083800_add_cert_md5.rb index 5efe4e596..4db005177 100644 --- a/db/data/20150601083800_add_cert_md5.rb +++ b/db/data/20150601083800_add_cert_md5.rb @@ -1,28 +1,27 @@ -class AddCertMd5 < ActiveRecord::Migration +class AddCertMd5 < ActiveRecord::Migration[5.1] def self.up - Certificate.all.each do |x| - if x.crt.present? && x.csr.present? - x.interface = Certificate::REGISTRAR - x.md5 = OpenSSL::Digest::MD5.new(x.parsed_crt.to_der).to_s - - pc = x.parsed_crt.try(:subject).try(:to_s) || '' - cn = pc.scan(/\/CN=(.+)/).flatten.first - x.common_name = cn.split('/').first - elsif x.crt.present? && x.csr.blank? - x.interface = Certificate::API - x.md5 = OpenSSL::Digest::MD5.new(x.parsed_crt.to_der).to_s - - pc = x.parsed_crt.try(:subject).try(:to_s) || '' - cn = pc.scan(/\/CN=(.+)/).flatten.first - x.common_name = cn.split('/').first - elsif x.crt.blank? && x.csr.present? - x.interface = Certificate::REGISTRAR - end - x.save - end + # Certificate.all.each do |x| + # if x.crt.present? && x.csr.present? + # x.interface = Certificate::REGISTRAR + # x.md5 = OpenSSL::Digest::MD5.new(x.parsed_crt.to_der).to_s + # + # pc = x.parsed_crt.try(:subject).try(:to_s) || '' + # cn = pc.scan(/\/CN=(.+)/).flatten.first + # x.common_name = cn.split('/').first + # elsif x.crt.present? && x.csr.blank? + # x.interface = Certificate::API + # x.md5 = OpenSSL::Digest::MD5.new(x.parsed_crt.to_der).to_s + # + # pc = x.parsed_crt.try(:subject).try(:to_s) || '' + # cn = pc.scan(/\/CN=(.+)/).flatten.first + # x.common_name = cn.split('/').first + # elsif x.crt.blank? && x.csr.present? + # x.interface = Certificate::REGISTRAR + # end + # x.save + # end end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20150609093515_add_renew_setting.rb b/db/data/20150609093515_add_renew_setting.rb index f462c38cb..2d99aa448 100644 --- a/db/data/20150609093515_add_renew_setting.rb +++ b/db/data/20150609093515_add_renew_setting.rb @@ -1,9 +1,8 @@ -class AddRenewSetting < ActiveRecord::Migration +class AddRenewSetting < ActiveRecord::Migration[5.1] def self.up - Setting.days_to_renew_domain_before_expire = 90 + # Setting.days_to_renew_domain_before_expire = 90 end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20150610111019_add_expire_settings.rb b/db/data/20150610111019_add_expire_settings.rb index 9f8b9cce8..6171536dd 100644 --- a/db/data/20150610111019_add_expire_settings.rb +++ b/db/data/20150610111019_add_expire_settings.rb @@ -1,10 +1,9 @@ -class AddExpireSettings < ActiveRecord::Migration +class AddExpireSettings < ActiveRecord::Migration[5.1] def self.up - Setting.expire_warning_period = 15 - Setting.redemption_grace_period = 30 + # Setting.expire_warning_period = 15 + # Setting.redemption_grace_period = 30 end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20150612125720_refactor_domain_statuses.rb b/db/data/20150612125720_refactor_domain_statuses.rb index 00e87b4d0..de0733e3f 100644 --- a/db/data/20150612125720_refactor_domain_statuses.rb +++ b/db/data/20150612125720_refactor_domain_statuses.rb @@ -1,15 +1,14 @@ -class RefactorDomainStatuses < ActiveRecord::Migration +class RefactorDomainStatuses < ActiveRecord::Migration[5.1] def self.up - Domain.find_each do |x| - statuses = [] - x.domain_statuses.each do |ds| - statuses << ds.value - end - x.update_column('statuses', statuses) - end + # Domain.find_each do |x| + # statuses = [] + # x.domain_statuses.each do |ds| + # statuses << ds.value + # end + # x.update_column('statuses', statuses) if x.statuses.blank? + # end end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20150707103801_refactor_contact_statuses.rb b/db/data/20150707103801_refactor_contact_statuses.rb index be6312016..e1833dd66 100644 --- a/db/data/20150707103801_refactor_contact_statuses.rb +++ b/db/data/20150707103801_refactor_contact_statuses.rb @@ -1,15 +1,14 @@ -class RefactorContactStatuses < ActiveRecord::Migration +class RefactorContactStatuses < ActiveRecord::Migration[5.1] def self.up - Contact.find_each do |contact| - statuses = [] - contact.depricated_statuses.each do |ds| - statuses << ds.value - end - contact.update_column('statuses', statuses) - end + # Contact.find_each do |contact| + # statuses = [] + # contact.depricated_statuses.each do |ds| + # statuses << ds.value + # end + # contact.update_column('statuses', statuses) + # end end def self.down - raise ActiveRecord::IrreversibleMigration end end diff --git a/db/data/20200225085234_convert_domain_delete_date.rb b/db/data/20200225085234_convert_domain_delete_date.rb new file mode 100644 index 000000000..81f070927 --- /dev/null +++ b/db/data/20200225085234_convert_domain_delete_date.rb @@ -0,0 +1,19 @@ +class ConvertDomainDeleteDate < ActiveRecord::Migration[5.1] + def up + # processed_domain_count = 0 + # + # Domain.transaction do + # Domain.find_each do |domain| + # next unless domain.delete_date + # + # domain.update_columns(delete_date: domain.delete_date + 1.day) + # processed_domain_count += 1 + # end + # end + # + # puts "Domains processed: #{processed_domain_count}" + end + + def down + end +end diff --git a/db/data/20200225085433_delete_orphaned_registrant_verifications.rb b/db/data/20200225085433_delete_orphaned_registrant_verifications.rb new file mode 100644 index 000000000..73c270a6a --- /dev/null +++ b/db/data/20200225085433_delete_orphaned_registrant_verifications.rb @@ -0,0 +1,18 @@ +class DeleteOrphanedRegistrantVerifications < ActiveRecord::Migration[5.1] + def up + # orphaned_registrant_verifications = RegistrantVerification.where.not(domain_id: Domain.ids) + # orphaned_registrant_verification_count = orphaned_registrant_verifications.count + # processed_registrant_verification_count = 0 + # + # orphaned_registrant_verifications.each do |registrant_verification| + # registrant_verification.destroy! + # processed_registrant_verification_count += 1 + # end + # + # puts "Processed: #{processed_registrant_verification_count} out of" \ + # " #{orphaned_registrant_verification_count}" + end + + def down + end +end diff --git a/db/data/20200225085539_regenerate_registrar_reference_numbers.rb b/db/data/20200225085539_regenerate_registrar_reference_numbers.rb new file mode 100644 index 000000000..fbd2a5c5f --- /dev/null +++ b/db/data/20200225085539_regenerate_registrar_reference_numbers.rb @@ -0,0 +1,19 @@ +class RegenerateRegistrarReferenceNumbers < ActiveRecord::Migration[5.1] + def up + # processed_registrar_count = 0 + # + # Registrar.transaction do + # Registrar.all.each do |registrar| + # next unless registrar.reference_no.start_with?('RF') + # + # registrar.update_columns(reference_no: Billing::ReferenceNo.generate) + # processed_registrar_count += 1 + # end + # end + # + # puts "Registrars processed: #{processed_registrar_count}" + end + + def down + end +end diff --git a/db/data/20200608084321_fill_email_verifications.rb b/db/data/20200608084321_fill_email_verifications.rb new file mode 100644 index 000000000..f1186983e --- /dev/null +++ b/db/data/20200608084321_fill_email_verifications.rb @@ -0,0 +1,21 @@ +class FillEmailVerifications < ActiveRecord::Migration[6.0] + include Concerns::EmailVerifable + + def up + # registrar_billing_emails = Registrar.pluck(:billing_email).uniq.reject(&:blank?) + # registrar_emails = Registrar.pluck(:email).uniq.reject(&:blank?) + # contact_emails = Contact.pluck(:email).uniq.reject(&:blank?) + # + # emails = (contact_emails + registrar_emails + registrar_billing_emails) + # emails = emails.map{ |email| punycode_to_unicode(email) }.uniq + # + # result = emails.map do |email| + # { email: email, domain: domain(email) } + # end + # EmailAddressVerification.import result, batch_size: 500 + end + + def down + EmailAddressVerification.delete_all + end +end diff --git a/db/data/20200702074549_fill_single_characted_blocked_domains.rb b/db/data/20200702074549_fill_single_characted_blocked_domains.rb new file mode 100644 index 000000000..da8bac9be --- /dev/null +++ b/db/data/20200702074549_fill_single_characted_blocked_domains.rb @@ -0,0 +1,20 @@ +class FillSingleCharactedBlockedDomains < ActiveRecord::Migration[6.0] + + DOMAIN_NAMES = %w[a.ee b.ee c.ee d.ee e.ee f.ee g.ee h.ee i.ee j.ee k.ee l.ee m.ee n.ee o.ee + p.ee q.ee r.ee s.ee š.ee z.ee ž.ee t.ee u.ee v.ee w.ee õ.ee ä.ee ö.ee ü.ee + x.ee y.ee 0.ee 1.ee 2.ee 3.ee 4.ee 5.ee 6.ee 7.ee 8.ee 9.ee].freeze + + def up + BlockedDomain.transaction do + DOMAIN_NAMES.each do |name| + BlockedDomain.find_or_create_by(name: name) + end + end + end + + def down + BlockedDomain.transaction do + BlockedDomain.by_domain(DOMAIN_NAMES).delete_all + end + end +end diff --git a/db/data/20200702104334_add_legal_document_mandatory_setting.rb b/db/data/20200702104334_add_legal_document_mandatory_setting.rb new file mode 100644 index 000000000..2e0a298f7 --- /dev/null +++ b/db/data/20200702104334_add_legal_document_mandatory_setting.rb @@ -0,0 +1,9 @@ +class AddLegalDocumentMandatorySetting < ActiveRecord::Migration[6.0] + def up + Setting.legal_document_is_mandatory = true + end + + def down + Setting.find_by(var: 'legal_document_is_mandatory').delete + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb new file mode 100644 index 000000000..7b35d4e7b --- /dev/null +++ b/db/data_schema.rb @@ -0,0 +1,2 @@ +# encoding: UTF-8 +DataMigrate::Data.define(version: 20200702104334) diff --git a/db/migrate/20180801114403_change_contacts_name_to_not_null.rb b/db/migrate/20180801114403_change_contacts_name_to_not_null.rb new file mode 100644 index 000000000..cfa4064ba --- /dev/null +++ b/db/migrate/20180801114403_change_contacts_name_to_not_null.rb @@ -0,0 +1,5 @@ +class ChangeContactsNameToNotNull < ActiveRecord::Migration + def change + change_column_null :contacts, :name, false + end +end \ No newline at end of file diff --git a/db/migrate/20191203083643_add_force_delete_start_to_domains.rb b/db/migrate/20191203083643_add_force_delete_start_to_domains.rb new file mode 100644 index 000000000..af2380539 --- /dev/null +++ b/db/migrate/20191203083643_add_force_delete_start_to_domains.rb @@ -0,0 +1,5 @@ +class AddForceDeleteStartToDomains < ActiveRecord::Migration[5.0] + def change + add_column :domains, :force_delete_start, :datetime + end +end diff --git a/db/migrate/20191206183853_remove_registrant_verifications_domain_name.rb b/db/migrate/20191206183853_remove_registrant_verifications_domain_name.rb new file mode 100644 index 000000000..0212c60ea --- /dev/null +++ b/db/migrate/20191206183853_remove_registrant_verifications_domain_name.rb @@ -0,0 +1,5 @@ +class RemoveRegistrantVerificationsDomainName < ActiveRecord::Migration[5.0] + def change + remove_column :registrant_verifications, :domain_name + end +end diff --git a/db/migrate/20191212133136_remove_fill_ident_country_function.rb b/db/migrate/20191212133136_remove_fill_ident_country_function.rb new file mode 100644 index 000000000..7a99ad855 --- /dev/null +++ b/db/migrate/20191212133136_remove_fill_ident_country_function.rb @@ -0,0 +1,7 @@ +class RemoveFillIdentCountryFunction < ActiveRecord::Migration[5.0] + def change + execute <<~SQL + DROP FUNCTION fill_ident_country(); + SQL + end +end diff --git a/db/migrate/20191227110904_add_json_based_version_to_registrant_verifications.rb b/db/migrate/20191227110904_add_json_based_version_to_registrant_verifications.rb new file mode 100644 index 000000000..6300cddf1 --- /dev/null +++ b/db/migrate/20191227110904_add_json_based_version_to_registrant_verifications.rb @@ -0,0 +1,24 @@ +class AddJsonBasedVersionToRegistrantVerifications < ActiveRecord::Migration[5.0] + def change + name = 'registrant_verification' + table_name = "log_#{name.tableize}" + + create_table table_name do |t| + t.string :item_type, null: false + t.integer :item_id, null: false + t.string :event, null: false + t.string :whodunnit + t.json :object + t.json :object_changes + t.datetime :created_at + t.string :session + end + add_index table_name, [:item_type, :item_id] + add_index table_name, :whodunnit + + add_column name.tableize, :creator_id_tmp, :integer + add_column name.tableize, :updater_id_tmp, :integer + rename_column name.tableize, :creator_id_tmp, :creator_id + rename_column name.tableize, :updater_id_tmp, :updater_id + end +end diff --git a/db/migrate/20200113091254_add_uuid_to_log_registrant_verification.rb b/db/migrate/20200113091254_add_uuid_to_log_registrant_verification.rb new file mode 100644 index 000000000..4e130fc8e --- /dev/null +++ b/db/migrate/20200113091254_add_uuid_to_log_registrant_verification.rb @@ -0,0 +1,7 @@ +class AddUuidToLogRegistrantVerification < ActiveRecord::Migration[5.0] + def change + change_table 'log_registrant_verifications' do |t| + t.string :uuid + end + end +end diff --git a/db/migrate/20200115102202_add_force_delete_data_to_domains.rb b/db/migrate/20200115102202_add_force_delete_data_to_domains.rb new file mode 100644 index 000000000..2ecc7ceaf --- /dev/null +++ b/db/migrate/20200115102202_add_force_delete_data_to_domains.rb @@ -0,0 +1,5 @@ +class AddForceDeleteDataToDomains < ActiveRecord::Migration[5.0] + def change + add_column :domains, :force_delete_data, :hstore + end +end diff --git a/db/migrate/20200130092113_create_payment_orders.rb b/db/migrate/20200130092113_create_payment_orders.rb new file mode 100644 index 000000000..97d86a034 --- /dev/null +++ b/db/migrate/20200130092113_create_payment_orders.rb @@ -0,0 +1,15 @@ +class CreatePaymentOrders < ActiveRecord::Migration[5.0] + def change + create_table :payment_orders do |t| + t.string :type, null: false + t.string :status, default: 'issued', null: false + t.belongs_to :invoice, foreign_key: true + t.jsonb :response, null: true + t.string :notes, null: true + t.string :creator_str + t.string :updator_str + + t.timestamps + end + end +end diff --git a/db/migrate/20200203143458_create_payment_order_versions.rb b/db/migrate/20200203143458_create_payment_order_versions.rb new file mode 100644 index 000000000..d02b300e1 --- /dev/null +++ b/db/migrate/20200203143458_create_payment_order_versions.rb @@ -0,0 +1,16 @@ +class CreatePaymentOrderVersions < ActiveRecord::Migration[5.0] + def change + create_table :log_payment_orders do |t| + t.string :item_type, null: false + t.integer :item_id, null: false + t.string :event, null: false + t.string :whodunnit + t.jsonb :object + t.jsonb :object_changes + t.datetime :created_at + t.string :session + t.jsonb :children + t.string :uuid + end + end +end diff --git a/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb b/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb new file mode 100644 index 000000000..e0e5f2cd0 --- /dev/null +++ b/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb @@ -0,0 +1,5 @@ +class AddEInvoiceSentAtToInvoice < ActiveRecord::Migration[5.0] + def change + add_column :invoices, :e_invoice_sent_at, :datetime + end +end diff --git a/db/migrate/20200311114649_update_zone_generation_migration.rb b/db/migrate/20200311114649_update_zone_generation_migration.rb new file mode 100644 index 000000000..2c516474d --- /dev/null +++ b/db/migrate/20200311114649_update_zone_generation_migration.rb @@ -0,0 +1,247 @@ +class UpdateZoneGenerationMigration < ActiveRecord::Migration[5.1] + def up + execute <<-SQL + CREATE OR REPLACE FUNCTION generate_zonefile(i_origin character varying) RETURNS text + LANGUAGE plpgsql + AS $_$ + DECLARE + zone_header text := concat('$ORIGIN ', i_origin, '.'); + serial_num varchar; + include_filter varchar := ''; + exclude_filter varchar := ''; + tmp_var text; + ret text; + BEGIN + -- define filters + include_filter = '%.' || i_origin; + + -- for %.%.% + IF i_origin ~ '.' THEN + exclude_filter := ''; + -- for %.% + ELSE + exclude_filter := '%.%.' || i_origin; + END IF; + + SELECT ROUND(extract(epoch from now() at time zone 'utc')) INTO serial_num; + + -- zonefile header + SELECT concat( + format('%-10s', '$ORIGIN .'), chr(10), + format('%-10s', '$TTL'), zf.ttl, chr(10), chr(10), + format('%-10s', i_origin || '.'), 'IN SOA ', zf.master_nameserver, '. ', zf.email, '. (', chr(10), + format('%-17s', ''), format('%-12s', serial_num), '; serial number', chr(10), + format('%-17s', ''), format('%-12s', zf.refresh), '; refresh, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.retry), '; retry, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.expire), '; expire, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.minimum_ttl), '; minimum TTL, seconds', chr(10), + format('%-17s', ''), ')' + ) FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + + ret = concat(tmp_var, chr(10), chr(10)); + + -- origin ns records + SELECT ns_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, chr(10)); + + -- ns records + SELECT array_to_string( + array( + SELECT concat(d.name_puny, '. IN NS ', coalesce(ns.hostname_puny, ns.hostname), '.') + FROM domains d + JOIN nameservers ns ON ns.domain_id = d.id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ORDER BY d.name + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin a glue records + SELECT a_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone A Records', chr(10), tmp_var, chr(10)); + + -- a glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(coalesce(ns.hostname_puny, ns.hostname), '. IN A ', unnest(ns.ipv4)) + FROM nameservers ns + JOIN domains d ON d.id = ns.domain_id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND (ns.hostname LIKE '%.' || d.name) OR (ns.hostname LIKE d.name) + AND d.name <> i_origin + AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '{}' + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin aaaa glue records + SELECT a4_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var, chr(10)); + + -- aaaa glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(coalesce(ns.hostname_puny, ns.hostname), '. IN AAAA ', unnest(ns.ipv6)) + FROM nameservers ns + JOIN domains d ON d.id = ns.domain_id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND (ns.hostname LIKE '%.' || d.name) OR (ns.hostname LIKE d.name) + AND d.name <> i_origin + AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '{}' + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- ds records + SELECT array_to_string( + array( + SELECT concat( + d.name_puny, '. 3600 IN DS ', dk.ds_key_tag, ' ', + dk.ds_alg, ' ', dk.ds_digest_type, ' ', dk.ds_digest + ) + FROM domains d + JOIN dnskeys dk ON dk.domain_id = d.id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter AND dk.flags = 257 + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, '; Zone DS Records', chr(10), tmp_var, chr(10)); + + RETURN ret; + END; + $_$; + SQL + end + + def down + execute <<-SQL + CREATE OR REPLACE FUNCTION generate_zonefile(i_origin character varying) RETURNS text + LANGUAGE plpgsql + AS $_$ + DECLARE + zone_header text := concat('$ORIGIN ', i_origin, '.'); + serial_num varchar; + include_filter varchar := ''; + exclude_filter varchar := ''; + tmp_var text; + ret text; + BEGIN + -- define filters + include_filter = '%.' || i_origin; + + -- for %.%.% + IF i_origin ~ '.' THEN + exclude_filter := ''; + -- for %.% + ELSE + exclude_filter := '%.%.' || i_origin; + END IF; + + SELECT ROUND(extract(epoch from now() at time zone 'utc')) INTO serial_num; + + -- zonefile header + SELECT concat( + format('%-10s', '$ORIGIN .'), chr(10), + format('%-10s', '$TTL'), zf.ttl, chr(10), chr(10), + format('%-10s', i_origin || '.'), 'IN SOA ', zf.master_nameserver, '. ', zf.email, '. (', chr(10), + format('%-17s', ''), format('%-12s', serial_num), '; serial number', chr(10), + format('%-17s', ''), format('%-12s', zf.refresh), '; refresh, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.retry), '; retry, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.expire), '; expire, seconds', chr(10), + format('%-17s', ''), format('%-12s', zf.minimum_ttl), '; minimum TTL, seconds', chr(10), + format('%-17s', ''), ')' + ) FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + + ret = concat(tmp_var, chr(10), chr(10)); + + -- origin ns records + SELECT ns_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, chr(10)); + + -- ns records + SELECT array_to_string( + array( + SELECT concat(d.name_puny, '. IN NS ', coalesce(ns.hostname_puny, ns.hostname), '.') + FROM domains d + JOIN nameservers ns ON ns.domain_id = d.id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ORDER BY d.name + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin a glue records + SELECT a_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone A Records', chr(10), tmp_var, chr(10)); + + -- a glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(coalesce(ns.hostname_puny, ns.hostname), '. IN A ', unnest(ns.ipv4)) + FROM nameservers ns + JOIN domains d ON d.id = ns.domain_id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND ns.hostname LIKE '%.' || d.name + AND d.name <> i_origin + AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '{}' + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin aaaa glue records + SELECT a4_records FROM zones zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var, chr(10)); + + -- aaaa glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(coalesce(ns.hostname_puny, ns.hostname), '. IN AAAA ', unnest(ns.ipv6)) + FROM nameservers ns + JOIN domains d ON d.id = ns.domain_id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter + AND ns.hostname LIKE '%.' || d.name + AND d.name <> i_origin + AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '{}' + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- ds records + SELECT array_to_string( + array( + SELECT concat( + d.name_puny, '. 3600 IN DS ', dk.ds_key_tag, ' ', + dk.ds_alg, ' ', dk.ds_digest_type, ' ', dk.ds_digest + ) + FROM domains d + JOIN dnskeys dk ON dk.domain_id = d.id + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter AND dk.flags = 257 + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, '; Zone DS Records', chr(10), tmp_var, chr(10)); + + RETURN ret; + END; + $_$; + SQL + end +end diff --git a/db/migrate/20200417075720_add_registration_deadline_date_to_models.rb b/db/migrate/20200417075720_add_registration_deadline_date_to_models.rb new file mode 100644 index 000000000..8614ec889 --- /dev/null +++ b/db/migrate/20200417075720_add_registration_deadline_date_to_models.rb @@ -0,0 +1,5 @@ +class AddRegistrationDeadlineDateToModels < ActiveRecord::Migration[5.2] + def change + add_column :auctions, :registration_deadline, :datetime + end +end diff --git a/db/migrate/20200421093637_create_disputes.rb b/db/migrate/20200421093637_create_disputes.rb new file mode 100644 index 000000000..b934d3297 --- /dev/null +++ b/db/migrate/20200421093637_create_disputes.rb @@ -0,0 +1,14 @@ +class CreateDisputes < ActiveRecord::Migration[5.2] + def change + create_table :disputes do |t| + t.string :domain_name, null: false + t.string :password, null: false + t.date :expires_at, null: false + t.date :starts_at, null: false + t.text :comment + t.boolean :closed, null: false, default: false + + t.timestamps + end + end +end diff --git a/db/migrate/20200505103316_add_revoked_to_certificate.rb b/db/migrate/20200505103316_add_revoked_to_certificate.rb new file mode 100644 index 000000000..a52c7d14c --- /dev/null +++ b/db/migrate/20200505103316_add_revoked_to_certificate.rb @@ -0,0 +1,5 @@ +class AddRevokedToCertificate < ActiveRecord::Migration[5.2] + def change + add_column :certificates, :revoked, :boolean, null: false, default: false + end +end diff --git a/db/migrate/20200505150413_add_dispute_period_in_months_to_setting.rb b/db/migrate/20200505150413_add_dispute_period_in_months_to_setting.rb new file mode 100644 index 000000000..cffa91b7f --- /dev/null +++ b/db/migrate/20200505150413_add_dispute_period_in_months_to_setting.rb @@ -0,0 +1,5 @@ +class AddDisputePeriodInMonthsToSetting < ActiveRecord::Migration[5.2] + def change + Setting.create(var: 'dispute_period_in_months', value: 36) + end +end diff --git a/db/migrate/20200518104105_add_closed_date_time_and_updator_to_dispute.rb b/db/migrate/20200518104105_add_closed_date_time_and_updator_to_dispute.rb new file mode 100644 index 000000000..1aae02e06 --- /dev/null +++ b/db/migrate/20200518104105_add_closed_date_time_and_updator_to_dispute.rb @@ -0,0 +1,19 @@ +class AddClosedDateTimeAndUpdatorToDispute < ActiveRecord::Migration[5.2] + def up + rename_column :disputes, :closed, :closed_boolean + add_column :disputes, :closed, :datetime + execute 'UPDATE disputes SET closed = updated_at WHERE closed_boolean = true' + execute 'UPDATE disputes SET closed = NULL WHERE closed_boolean = false' + remove_column :disputes, :closed_boolean + add_column :disputes, :initiator, :string + end + + def down + rename_column :disputes, :closed, :closed_datetime + add_column :disputes, :closed, :boolean, null: false, default: false + execute 'UPDATE disputes SET closed = true WHERE closed_datetime != NULL' + execute 'UPDATE disputes SET closed = false WHERE closed_datetime = NULL' + remove_column :disputes, :closed_datetime + remove_column :disputes, :initiator + end +end diff --git a/db/migrate/20200529115011_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb b/db/migrate/20200529115011_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb new file mode 100644 index 000000000..ff5d72c7e --- /dev/null +++ b/db/migrate/20200529115011_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb @@ -0,0 +1,10 @@ +# This migration comes from active_storage (originally 20180723000244) +class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] + def up + return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) + + if table_exists?(:active_storage_blobs) + add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id + end + end +end diff --git a/db/migrate/20200605100827_create_email_address_verifications.rb b/db/migrate/20200605100827_create_email_address_verifications.rb new file mode 100644 index 000000000..7f618b3a7 --- /dev/null +++ b/db/migrate/20200605100827_create_email_address_verifications.rb @@ -0,0 +1,13 @@ +class CreateEmailAddressVerifications < ActiveRecord::Migration[6.0] + def change + create_table :email_address_verifications do |t| + t.string :email, null: false + t.datetime :verified_at + t.boolean :success, null: false, default: false + t.string :domain, null: false + end + + add_index :email_address_verifications, :email, unique: true + add_index :email_address_verifications, :domain + end +end diff --git a/db/migrate/20200610090110_change_email_verification_fields_to_citext.rb b/db/migrate/20200610090110_change_email_verification_fields_to_citext.rb new file mode 100644 index 000000000..a7e2f8ee8 --- /dev/null +++ b/db/migrate/20200610090110_change_email_verification_fields_to_citext.rb @@ -0,0 +1,13 @@ +class ChangeEmailVerificationFieldsToCitext < ActiveRecord::Migration[6.0] + def up + enable_extension 'citext' + change_column :email_address_verifications, :email, :citext + change_column :email_address_verifications, :domain, :citext + end + + def down + change_column :email_address_verifications, :email, :string + change_column :email_address_verifications, :domain, :string + disable_extension 'citext' + end +end diff --git a/db/migrate/20200630081231_add_legal_doc_optout_to_registrar.rb b/db/migrate/20200630081231_add_legal_doc_optout_to_registrar.rb new file mode 100644 index 000000000..e5bc5a7f1 --- /dev/null +++ b/db/migrate/20200630081231_add_legal_doc_optout_to_registrar.rb @@ -0,0 +1,6 @@ +class AddLegalDocOptoutToRegistrar < ActiveRecord::Migration[6.0] + def change + add_column :registrars, :legaldoc_optout, :boolean, null: false, default: false + add_column :registrars, :legaldoc_optout_comment, :text + end +end diff --git a/db/migrate/20200714115338_add_unique_constraints_to_domain_objects.rb b/db/migrate/20200714115338_add_unique_constraints_to_domain_objects.rb new file mode 100644 index 000000000..8c1b25c73 --- /dev/null +++ b/db/migrate/20200714115338_add_unique_constraints_to_domain_objects.rb @@ -0,0 +1,36 @@ +class AddUniqueConstraintsToDomainObjects < ActiveRecord::Migration[6.0] + def up + + execute <<-SQL + alter table domain_contacts + drop constraint if exists uniq_contact_of_type_per_domain; + SQL + + execute <<-SQL + alter table nameservers + drop constraint if exists uniq_hostname_per_domain; + SQL + + execute <<-SQL + alter table domain_contacts + add constraint uniq_contact_of_type_per_domain unique (domain_id, type, contact_id); + SQL + + execute <<-SQL + alter table nameservers + add constraint uniq_hostname_per_domain unique (domain_id, hostname); + SQL + end + + def down + execute <<-SQL + alter table domain_contacts + drop constraint if exists uniq_contact_of_type_per_domain; + SQL + + execute <<-SQL + alter table nameservers + drop constraint if exists uniq_hostname_per_domain; + SQL + end +end diff --git a/db/migrate/20200807110611_change_registrant_verification_creator_updator_id_to_string.rb b/db/migrate/20200807110611_change_registrant_verification_creator_updator_id_to_string.rb new file mode 100644 index 000000000..144a80ceb --- /dev/null +++ b/db/migrate/20200807110611_change_registrant_verification_creator_updator_id_to_string.rb @@ -0,0 +1,9 @@ +class ChangeRegistrantVerificationCreatorUpdatorIdToString < ActiveRecord::Migration[6.0] + def change + add_column :registrant_verifications, :creator_str, :string + add_column :registrant_verifications, :updator_str, :string + + remove_column :registrant_verifications, :creator_id + remove_column :registrant_verifications, :updater_id + end +end diff --git a/db/structure.sql b/db/structure.sql index de94f1eae..59492ff4a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,6 +1,6 @@ --- --- PostgreSQL database dump --- +--- +--- PostgreSQL database dump +--- SET statement_timeout = 0; SET lock_timeout = 0; @@ -8,6 +8,7 @@ SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies = false; +SET xmloption = content; SET client_min_messages = warning; -- @@ -30,12 +31,18 @@ COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; CREATE EXTENSION IF NOT EXISTS btree_gist WITH SCHEMA public; - -- --- Name: EXTENSION btree_gist; Type: COMMENT; Schema: -; Owner: - +-- Name: citext; Type: EXTENSION; Schema: -; Owner: - -- -COMMENT ON EXTENSION btree_gist IS 'support for indexing common datatypes in GiST'; +CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public; + + +-- +-- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings'; -- @@ -66,106 +73,6 @@ CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public; COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; --- --- Name: fill_ident_country(); Type: FUNCTION; Schema: public; Owner: - --- - -CREATE FUNCTION public.fill_ident_country() RETURNS boolean - LANGUAGE plpgsql - AS $_$ - DECLARE - changed BOOLEAN; - multiplier INT []; - multiplier2 INT []; - multiplier3 INT []; - multiplier4 INT []; - r RECORD; - control TEXT; - total INT; - i INT; - mod INT; - counter INT; - BEGIN - - multiplier := ARRAY [1, 2, 3, 4, 5, 6, 7, 8, 9, 1]; - multiplier2 := ARRAY [3, 4, 5, 6, 7, 8, 9, 1, 2, 3]; - multiplier3 := ARRAY [1, 2, 3, 4, 5, 6, 7]; - multiplier4 := ARRAY [3, 4, 5, 6, 7, 8, 9]; - - FOR r IN SELECT id, ident FROM contacts WHERE ident_type = 'priv' AND ident_country_code IS NULL - LOOP - IF (length(r.ident) = 11 AND (r.ident ~ '^[0-9]+$') AND (substring(r.ident, 1, 1) = '3' OR substring(r.ident, 1, 1) = '4' OR substring(r.ident, 1, 1) = '5' OR substring(r.ident, 1, 1) = '6')) - THEN - total := 0; - counter := 1; - FOREACH i IN ARRAY multiplier - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - counter := 1; - IF (mod >= 10) - THEN - total = 0; - FOREACH i IN ARRAY multiplier2 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - END IF; - IF (mod = 10) - THEN - mod := 0; - END IF; - IF (substring(r.ident, 11, 1) = to_char(mod, 'FM999MI')) - THEN - UPDATE contacts SET ident_country_code = 'EE' WHERE id = r.id; - END IF; - total := 0; - END IF; - END LOOP; - - FOR r IN SELECT id, ident FROM contacts WHERE ident_type = 'org' AND ident_country_code IS NULL - LOOP - IF (length(r.ident) = 8 AND (r.ident ~ '^[0-9]+$') AND (substring(r.ident, 1, 1) = '1' OR substring(r.ident, 1, 1) = '8' OR substring(r.ident, 1, 1) = '9')) - THEN - total := 0; - counter := 1; - FOREACH i IN ARRAY multiplier3 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := total % 11; - total := 0; - counter := 1; - IF (mod >= 10) - THEN - total = 0; - FOREACH i IN ARRAY multiplier4 - LOOP - total := (total + (i * to_number(substring(r.ident, counter, 1), '9'))); - counter := (counter + 1); - END LOOP; - mod := (total % 11); - END IF; - IF (mod = 10) - THEN - mod := 0; - END IF; - IF (substring(r.ident, 8, 1) = to_char(mod, 'FM999MI')) - THEN - UPDATE contacts SET ident_country_code = 'EE' WHERE id = r.id; - END IF; - END IF; - END LOOP; - RETURN changed; - END; - $_$; - - -- -- Name: generate_zonefile(character varying); Type: FUNCTION; Schema: public; Owner: - -- @@ -239,7 +146,7 @@ CREATE FUNCTION public.generate_zonefile(i_origin character varying) RETURNS tex FROM nameservers ns JOIN domains d ON d.id = ns.domain_id WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter - AND ns.hostname LIKE '%.' || d.name + AND (ns.hostname LIKE '%.' || d.name) OR (ns.hostname LIKE d.name) AND d.name <> i_origin AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> '{}' AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) @@ -259,7 +166,7 @@ CREATE FUNCTION public.generate_zonefile(i_origin character varying) RETURNS tex FROM nameservers ns JOIN domains d ON d.id = ns.domain_id WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter - AND ns.hostname LIKE '%.' || d.name + AND (ns.hostname LIKE '%.' || d.name) OR (ns.hostname LIKE d.name) AND d.name <> i_origin AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> '{}' AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) @@ -295,7 +202,7 @@ SET default_tablespace = ''; SET default_with_oids = false; -- --- Name: account_activities; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: account_activities; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.account_activities ( @@ -335,7 +242,7 @@ ALTER SEQUENCE public.account_activities_id_seq OWNED BY public.account_activiti -- --- Name: accounts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: accounts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.accounts ( @@ -371,7 +278,7 @@ ALTER SEQUENCE public.accounts_id_seq OWNED BY public.accounts.id; -- --- Name: actions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: actions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.actions ( @@ -403,7 +310,19 @@ ALTER SEQUENCE public.actions_id_seq OWNED BY public.actions.id; -- --- Name: auctions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.ar_internal_metadata ( + key character varying NOT NULL, + value character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: auctions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.auctions ( @@ -412,7 +331,8 @@ CREATE TABLE public.auctions ( status character varying NOT NULL, uuid uuid DEFAULT public.gen_random_uuid() NOT NULL, created_at timestamp without time zone NOT NULL, - registration_code character varying + registration_code character varying, + registration_deadline timestamp without time zone ); @@ -436,7 +356,7 @@ ALTER SEQUENCE public.auctions_id_seq OWNED BY public.auctions.id; -- --- Name: bank_statements; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: bank_statements; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.bank_statements ( @@ -472,7 +392,7 @@ ALTER SEQUENCE public.bank_statements_id_seq OWNED BY public.bank_statements.id; -- --- Name: bank_transactions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: bank_transactions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.bank_transactions ( @@ -516,7 +436,7 @@ ALTER SEQUENCE public.bank_transactions_id_seq OWNED BY public.bank_transactions -- --- Name: blocked_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: blocked_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.blocked_domains ( @@ -549,7 +469,7 @@ ALTER SEQUENCE public.blocked_domains_id_seq OWNED BY public.blocked_domains.id; -- --- Name: certificates; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: certificates; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.certificates ( @@ -563,7 +483,8 @@ CREATE TABLE public.certificates ( updated_at timestamp without time zone, common_name character varying, md5 character varying, - interface character varying + interface character varying, + revoked boolean DEFAULT false NOT NULL ); @@ -587,7 +508,7 @@ ALTER SEQUENCE public.certificates_id_seq OWNED BY public.certificates.id; -- --- Name: contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.contacts ( @@ -601,7 +522,7 @@ CREATE TABLE public.contacts ( ident character varying, ident_type character varying, auth_info character varying NOT NULL, - name character varying, + name character varying NOT NULL, org_name character varying, registrar_id integer NOT NULL, creator_str character varying, @@ -645,7 +566,16 @@ ALTER SEQUENCE public.contacts_id_seq OWNED BY public.contacts.id; -- --- Name: directos; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: data_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.data_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: directos; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.directos ( @@ -680,7 +610,44 @@ ALTER SEQUENCE public.directos_id_seq OWNED BY public.directos.id; -- --- Name: dnskeys; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: disputes; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.disputes ( + id bigint NOT NULL, + domain_name character varying NOT NULL, + password character varying NOT NULL, + expires_at date NOT NULL, + starts_at date NOT NULL, + comment text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + closed timestamp without time zone, + initiator character varying +); + + +-- +-- Name: disputes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.disputes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: disputes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.disputes_id_seq OWNED BY public.disputes.id; + + +-- +-- Name: dnskeys; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.dnskeys ( @@ -721,7 +688,7 @@ ALTER SEQUENCE public.dnskeys_id_seq OWNED BY public.dnskeys.id; -- --- Name: domain_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: domain_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.domain_contacts ( @@ -759,7 +726,7 @@ ALTER SEQUENCE public.domain_contacts_id_seq OWNED BY public.domain_contacts.id; -- --- Name: domain_transfers; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: domain_transfers; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.domain_transfers ( @@ -796,7 +763,7 @@ ALTER SEQUENCE public.domain_transfers_id_seq OWNED BY public.domain_transfers.i -- --- Name: domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.domains ( @@ -830,7 +797,9 @@ CREATE TABLE public.domains ( upid integer, up_date timestamp without time zone, uuid uuid DEFAULT public.gen_random_uuid() NOT NULL, - locked_by_registrant_at timestamp without time zone + locked_by_registrant_at timestamp without time zone, + force_delete_start timestamp without time zone, + force_delete_data public.hstore ); @@ -854,7 +823,99 @@ ALTER SEQUENCE public.domains_id_seq OWNED BY public.domains.id; -- --- Name: epp_sessions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: email_address_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.email_address_verifications ( + id bigint NOT NULL, + email public.citext NOT NULL, + verified_at timestamp without time zone, + success boolean DEFAULT false NOT NULL, + domain public.citext NOT NULL +); + + +-- +-- Name: email_address_verifications_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.email_address_verifications_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: email_address_verifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.email_address_verifications_id_seq OWNED BY public.email_address_verifications.id; + + +-- +-- Name: email_addresses_validations; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.email_addresses_validations ( + id bigint NOT NULL, + email character varying NOT NULL, + validated_at timestamp without time zone +); + + +-- +-- Name: email_addresses_validations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.email_addresses_validations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: email_addresses_validations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.email_addresses_validations_id_seq OWNED BY public.email_addresses_validations.id; + + +-- +-- Name: email_addresses_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.email_addresses_verifications ( + id bigint NOT NULL, + email character varying NOT NULL, + validated_at timestamp without time zone +); + + +-- +-- Name: email_addresses_verifications_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.email_addresses_verifications_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: email_addresses_verifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.email_addresses_verifications_id_seq OWNED BY public.email_addresses_verifications.id; + + +-- +-- Name: epp_sessions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.epp_sessions ( @@ -886,7 +947,7 @@ ALTER SEQUENCE public.epp_sessions_id_seq OWNED BY public.epp_sessions.id; -- --- Name: invoice_items; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: invoice_items; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.invoice_items ( @@ -924,7 +985,7 @@ ALTER SEQUENCE public.invoice_items_id_seq OWNED BY public.invoice_items.id; -- --- Name: invoices; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: invoices; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.invoices ( @@ -970,6 +1031,7 @@ CREATE TABLE public.invoices ( in_directo boolean DEFAULT false, buyer_vat_no character varying, issue_date date NOT NULL, + e_invoice_sent_at timestamp without time zone, CONSTRAINT invoices_due_date_is_not_before_issue_date CHECK ((due_date >= issue_date)) ); @@ -994,7 +1056,7 @@ ALTER SEQUENCE public.invoices_id_seq OWNED BY public.invoices.id; -- --- Name: legal_documents; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: legal_documents; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.legal_documents ( @@ -1029,7 +1091,7 @@ ALTER SEQUENCE public.legal_documents_id_seq OWNED BY public.legal_documents.id; -- --- Name: log_account_activities; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_account_activities; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_account_activities ( @@ -1067,7 +1129,7 @@ ALTER SEQUENCE public.log_account_activities_id_seq OWNED BY public.log_account_ -- --- Name: log_accounts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_accounts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_accounts ( @@ -1105,7 +1167,7 @@ ALTER SEQUENCE public.log_accounts_id_seq OWNED BY public.log_accounts.id; -- --- Name: log_actions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_actions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_actions ( @@ -1143,7 +1205,7 @@ ALTER SEQUENCE public.log_actions_id_seq OWNED BY public.log_actions.id; -- --- Name: log_bank_statements; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_bank_statements; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_bank_statements ( @@ -1181,7 +1243,7 @@ ALTER SEQUENCE public.log_bank_statements_id_seq OWNED BY public.log_bank_statem -- --- Name: log_bank_transactions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_bank_transactions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_bank_transactions ( @@ -1219,7 +1281,7 @@ ALTER SEQUENCE public.log_bank_transactions_id_seq OWNED BY public.log_bank_tran -- --- Name: log_blocked_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_blocked_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_blocked_domains ( @@ -1257,7 +1319,7 @@ ALTER SEQUENCE public.log_blocked_domains_id_seq OWNED BY public.log_blocked_dom -- --- Name: log_certificates; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_certificates; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_certificates ( @@ -1295,7 +1357,7 @@ ALTER SEQUENCE public.log_certificates_id_seq OWNED BY public.log_certificates.i -- --- Name: log_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_contacts ( @@ -1334,7 +1396,7 @@ ALTER SEQUENCE public.log_contacts_id_seq OWNED BY public.log_contacts.id; -- --- Name: log_dnskeys; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_dnskeys; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_dnskeys ( @@ -1372,7 +1434,7 @@ ALTER SEQUENCE public.log_dnskeys_id_seq OWNED BY public.log_dnskeys.id; -- --- Name: log_domain_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_domain_contacts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_domain_contacts ( @@ -1410,7 +1472,7 @@ ALTER SEQUENCE public.log_domain_contacts_id_seq OWNED BY public.log_domain_cont -- --- Name: log_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_domains ( @@ -1448,7 +1510,7 @@ ALTER SEQUENCE public.log_domains_id_seq OWNED BY public.log_domains.id; -- --- Name: log_invoice_items; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_invoice_items; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_invoice_items ( @@ -1486,7 +1548,7 @@ ALTER SEQUENCE public.log_invoice_items_id_seq OWNED BY public.log_invoice_items -- --- Name: log_invoices; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_invoices; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_invoices ( @@ -1524,7 +1586,7 @@ ALTER SEQUENCE public.log_invoices_id_seq OWNED BY public.log_invoices.id; -- --- Name: log_nameservers; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_nameservers; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_nameservers ( @@ -1562,7 +1624,7 @@ ALTER SEQUENCE public.log_nameservers_id_seq OWNED BY public.log_nameservers.id; -- --- Name: log_notifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_notifications; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_notifications ( @@ -1600,7 +1662,82 @@ ALTER SEQUENCE public.log_notifications_id_seq OWNED BY public.log_notifications -- --- Name: log_registrars; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_payment_orders; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.log_payment_orders ( + id integer NOT NULL, + item_type character varying NOT NULL, + item_id integer NOT NULL, + event character varying NOT NULL, + whodunnit character varying, + object jsonb, + object_changes jsonb, + created_at timestamp without time zone, + session character varying, + children jsonb, + uuid character varying +); + + +-- +-- Name: log_payment_orders_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.log_payment_orders_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: log_payment_orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.log_payment_orders_id_seq OWNED BY public.log_payment_orders.id; + + +-- +-- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.log_registrant_verifications ( + id integer NOT NULL, + item_type character varying NOT NULL, + item_id integer NOT NULL, + event character varying NOT NULL, + whodunnit character varying, + object json, + object_changes json, + created_at timestamp without time zone, + session character varying, + uuid character varying +); + + +-- +-- Name: log_registrant_verifications_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.log_registrant_verifications_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: log_registrant_verifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.log_registrant_verifications_id_seq OWNED BY public.log_registrant_verifications.id; + + +-- +-- Name: log_registrars; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_registrars ( @@ -1638,7 +1775,7 @@ ALTER SEQUENCE public.log_registrars_id_seq OWNED BY public.log_registrars.id; -- --- Name: log_reserved_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_reserved_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_reserved_domains ( @@ -1676,7 +1813,7 @@ ALTER SEQUENCE public.log_reserved_domains_id_seq OWNED BY public.log_reserved_d -- --- Name: log_settings; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_settings; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_settings ( @@ -1714,7 +1851,7 @@ ALTER SEQUENCE public.log_settings_id_seq OWNED BY public.log_settings.id; -- --- Name: log_users; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_users; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_users ( @@ -1752,7 +1889,7 @@ ALTER SEQUENCE public.log_users_id_seq OWNED BY public.log_users.id; -- --- Name: log_white_ips; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: log_white_ips; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.log_white_ips ( @@ -1790,7 +1927,7 @@ ALTER SEQUENCE public.log_white_ips_id_seq OWNED BY public.log_white_ips.id; -- --- Name: nameservers; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: nameservers; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.nameservers ( @@ -1828,7 +1965,7 @@ ALTER SEQUENCE public.nameservers_id_seq OWNED BY public.nameservers.id; -- --- Name: notifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: notifications; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.notifications ( @@ -1866,7 +2003,44 @@ ALTER SEQUENCE public.notifications_id_seq OWNED BY public.notifications.id; -- --- Name: prices; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: payment_orders; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE public.payment_orders ( + id integer NOT NULL, + type character varying NOT NULL, + status character varying DEFAULT 'issued'::character varying NOT NULL, + invoice_id integer, + response jsonb, + notes character varying, + creator_str character varying, + updator_str character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: payment_orders_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.payment_orders_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: payment_orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.payment_orders_id_seq OWNED BY public.payment_orders.id; + + +-- +-- Name: prices; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.prices ( @@ -1904,7 +2078,7 @@ ALTER SEQUENCE public.prices_id_seq OWNED BY public.prices.id; -- --- Name: que_jobs; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: que_jobs; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.que_jobs ( @@ -1946,18 +2120,19 @@ ALTER SEQUENCE public.que_jobs_job_id_seq OWNED BY public.que_jobs.job_id; -- --- Name: registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.registrant_verifications ( id integer NOT NULL, - domain_name character varying NOT NULL, verification_token character varying NOT NULL, created_at timestamp without time zone, updated_at timestamp without time zone, action character varying NOT NULL, domain_id integer NOT NULL, - action_type character varying NOT NULL + action_type character varying NOT NULL, + creator_str character varying, + updator_str character varying ); @@ -1981,7 +2156,7 @@ ALTER SEQUENCE public.registrant_verifications_id_seq OWNED BY public.registrant -- --- Name: registrars; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: registrars; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.registrars ( @@ -2010,7 +2185,9 @@ CREATE TABLE public.registrars ( language character varying NOT NULL, vat_rate numeric(4,3), iban character varying, - settings jsonb DEFAULT '{}'::jsonb NOT NULL + settings jsonb DEFAULT '{}'::jsonb NOT NULL, + legaldoc_optout boolean DEFAULT false NOT NULL, + legaldoc_optout_comment text ); @@ -2034,7 +2211,7 @@ ALTER SEQUENCE public.registrars_id_seq OWNED BY public.registrars.id; -- --- Name: reserved_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: reserved_domains; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.reserved_domains ( @@ -2069,7 +2246,7 @@ ALTER SEQUENCE public.reserved_domains_id_seq OWNED BY public.reserved_domains.i -- --- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.schema_migrations ( @@ -2078,7 +2255,7 @@ CREATE TABLE public.schema_migrations ( -- --- Name: settings; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: settings; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.settings ( @@ -2114,7 +2291,7 @@ ALTER SEQUENCE public.settings_id_seq OWNED BY public.settings.id; -- --- Name: users; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: users; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.users ( @@ -2166,7 +2343,7 @@ ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; -- --- Name: versions; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: versions; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.versions ( @@ -2201,7 +2378,7 @@ ALTER SEQUENCE public.versions_id_seq OWNED BY public.versions.id; -- --- Name: white_ips; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: white_ips; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.white_ips ( @@ -2237,7 +2414,7 @@ ALTER SEQUENCE public.white_ips_id_seq OWNED BY public.white_ips.id; -- --- Name: whois_records; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: whois_records; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.whois_records ( @@ -2272,7 +2449,7 @@ ALTER SEQUENCE public.whois_records_id_seq OWNED BY public.whois_records.id; -- --- Name: zones; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- Name: zones; Type: TABLE; Schema: public; Owner: -; Tablespace: -- CREATE TABLE public.zones ( @@ -2384,6 +2561,13 @@ ALTER TABLE ONLY public.contacts ALTER COLUMN id SET DEFAULT nextval('public.con ALTER TABLE ONLY public.directos ALTER COLUMN id SET DEFAULT nextval('public.directos_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.disputes ALTER COLUMN id SET DEFAULT nextval('public.disputes_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2412,6 +2596,27 @@ ALTER TABLE ONLY public.domain_transfers ALTER COLUMN id SET DEFAULT nextval('pu ALTER TABLE ONLY public.domains ALTER COLUMN id SET DEFAULT nextval('public.domains_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.email_address_verifications ALTER COLUMN id SET DEFAULT nextval('public.email_address_verifications_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.email_addresses_validations ALTER COLUMN id SET DEFAULT nextval('public.email_addresses_validations_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.email_addresses_verifications ALTER COLUMN id SET DEFAULT nextval('public.email_addresses_verifications_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2545,6 +2750,20 @@ ALTER TABLE ONLY public.log_nameservers ALTER COLUMN id SET DEFAULT nextval('pub ALTER TABLE ONLY public.log_notifications ALTER COLUMN id SET DEFAULT nextval('public.log_notifications_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.log_payment_orders ALTER COLUMN id SET DEFAULT nextval('public.log_payment_orders_id_seq'::regclass); + + +-- +-- 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); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2594,6 +2813,13 @@ ALTER TABLE ONLY public.nameservers ALTER COLUMN id SET DEFAULT nextval('public. ALTER TABLE ONLY public.notifications ALTER COLUMN id SET DEFAULT nextval('public.notifications_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_orders ALTER COLUMN id SET DEFAULT nextval('public.payment_orders_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -2672,7 +2898,7 @@ ALTER TABLE ONLY public.zones ALTER COLUMN id SET DEFAULT nextval('public.zones_ -- --- Name: account_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: account_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.account_activities @@ -2680,7 +2906,7 @@ ALTER TABLE ONLY public.account_activities -- --- Name: accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.accounts @@ -2688,7 +2914,7 @@ ALTER TABLE ONLY public.accounts -- --- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.actions @@ -2696,7 +2922,15 @@ ALTER TABLE ONLY public.actions -- --- Name: auctions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.ar_internal_metadata + ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); + + +-- +-- Name: auctions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.auctions @@ -2704,7 +2938,7 @@ ALTER TABLE ONLY public.auctions -- --- Name: bank_statements_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: bank_statements_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.bank_statements @@ -2712,7 +2946,7 @@ ALTER TABLE ONLY public.bank_statements -- --- Name: bank_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: bank_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.bank_transactions @@ -2720,7 +2954,7 @@ ALTER TABLE ONLY public.bank_transactions -- --- Name: blocked_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: blocked_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.blocked_domains @@ -2728,7 +2962,7 @@ ALTER TABLE ONLY public.blocked_domains -- --- Name: certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.certificates @@ -2736,7 +2970,7 @@ ALTER TABLE ONLY public.certificates -- --- Name: contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.contacts @@ -2744,7 +2978,7 @@ ALTER TABLE ONLY public.contacts -- --- Name: directos_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: directos_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.directos @@ -2752,7 +2986,15 @@ ALTER TABLE ONLY public.directos -- --- Name: dnskeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: disputes_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.disputes + ADD CONSTRAINT disputes_pkey PRIMARY KEY (id); + + +-- +-- Name: dnskeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.dnskeys @@ -2760,7 +3002,7 @@ ALTER TABLE ONLY public.dnskeys -- --- Name: domain_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: domain_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.domain_contacts @@ -2768,7 +3010,7 @@ ALTER TABLE ONLY public.domain_contacts -- --- Name: domain_transfers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: domain_transfers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.domain_transfers @@ -2776,7 +3018,7 @@ ALTER TABLE ONLY public.domain_transfers -- --- Name: domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.domains @@ -2784,7 +3026,31 @@ ALTER TABLE ONLY public.domains -- --- Name: epp_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: email_address_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.email_address_verifications + ADD CONSTRAINT email_address_verifications_pkey PRIMARY KEY (id); + + +-- +-- Name: email_addresses_validations_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.email_addresses_validations + ADD CONSTRAINT email_addresses_validations_pkey PRIMARY KEY (id); + + +-- +-- Name: email_addresses_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.email_addresses_verifications + ADD CONSTRAINT email_addresses_verifications_pkey PRIMARY KEY (id); + + +-- +-- Name: epp_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.epp_sessions @@ -2792,7 +3058,7 @@ ALTER TABLE ONLY public.epp_sessions -- --- Name: invoice_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: invoice_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.invoice_items @@ -2800,7 +3066,7 @@ ALTER TABLE ONLY public.invoice_items -- --- Name: invoices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: invoices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.invoices @@ -2808,7 +3074,7 @@ ALTER TABLE ONLY public.invoices -- --- Name: legal_documents_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: legal_documents_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.legal_documents @@ -2816,7 +3082,7 @@ ALTER TABLE ONLY public.legal_documents -- --- Name: log_account_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_account_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_account_activities @@ -2824,7 +3090,7 @@ ALTER TABLE ONLY public.log_account_activities -- --- Name: log_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_accounts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_accounts @@ -2832,7 +3098,7 @@ ALTER TABLE ONLY public.log_accounts -- --- Name: log_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_actions @@ -2840,7 +3106,7 @@ ALTER TABLE ONLY public.log_actions -- --- Name: log_bank_statements_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_bank_statements_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_bank_statements @@ -2848,7 +3114,7 @@ ALTER TABLE ONLY public.log_bank_statements -- --- Name: log_bank_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_bank_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_bank_transactions @@ -2856,7 +3122,7 @@ ALTER TABLE ONLY public.log_bank_transactions -- --- Name: log_blocked_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_blocked_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_blocked_domains @@ -2864,7 +3130,7 @@ ALTER TABLE ONLY public.log_blocked_domains -- --- Name: log_certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_certificates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_certificates @@ -2872,7 +3138,7 @@ ALTER TABLE ONLY public.log_certificates -- --- Name: log_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_contacts @@ -2880,7 +3146,7 @@ ALTER TABLE ONLY public.log_contacts -- --- Name: log_dnskeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_dnskeys_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_dnskeys @@ -2888,7 +3154,7 @@ ALTER TABLE ONLY public.log_dnskeys -- --- Name: log_domain_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_domain_contacts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_domain_contacts @@ -2896,7 +3162,7 @@ ALTER TABLE ONLY public.log_domain_contacts -- --- Name: log_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_domains @@ -2904,7 +3170,7 @@ ALTER TABLE ONLY public.log_domains -- --- Name: log_invoice_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_invoice_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_invoice_items @@ -2912,7 +3178,7 @@ ALTER TABLE ONLY public.log_invoice_items -- --- Name: log_invoices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_invoices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_invoices @@ -2920,7 +3186,7 @@ ALTER TABLE ONLY public.log_invoices -- --- Name: log_nameservers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_nameservers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_nameservers @@ -2928,7 +3194,7 @@ ALTER TABLE ONLY public.log_nameservers -- --- Name: log_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_notifications @@ -2936,7 +3202,23 @@ ALTER TABLE ONLY public.log_notifications -- --- Name: log_registrars_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_payment_orders_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.log_payment_orders + ADD CONSTRAINT log_payment_orders_pkey PRIMARY KEY (id); + + +-- +-- Name: log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.log_registrant_verifications + ADD CONSTRAINT log_registrant_verifications_pkey PRIMARY KEY (id); + + +-- +-- Name: log_registrars_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_registrars @@ -2944,7 +3226,7 @@ ALTER TABLE ONLY public.log_registrars -- --- Name: log_reserved_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_reserved_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_reserved_domains @@ -2952,7 +3234,7 @@ ALTER TABLE ONLY public.log_reserved_domains -- --- Name: log_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_settings @@ -2960,7 +3242,7 @@ ALTER TABLE ONLY public.log_settings -- --- Name: log_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_users @@ -2968,7 +3250,7 @@ ALTER TABLE ONLY public.log_users -- --- Name: log_white_ips_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: log_white_ips_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.log_white_ips @@ -2976,7 +3258,7 @@ ALTER TABLE ONLY public.log_white_ips -- --- Name: nameservers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: nameservers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.nameservers @@ -2984,7 +3266,7 @@ ALTER TABLE ONLY public.nameservers -- --- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.notifications @@ -2992,7 +3274,15 @@ ALTER TABLE ONLY public.notifications -- --- Name: prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: payment_orders_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.payment_orders + ADD CONSTRAINT payment_orders_pkey PRIMARY KEY (id); + + +-- +-- Name: prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.prices @@ -3000,7 +3290,7 @@ ALTER TABLE ONLY public.prices -- --- Name: que_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: que_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.que_jobs @@ -3008,7 +3298,7 @@ ALTER TABLE ONLY public.que_jobs -- --- Name: registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.registrant_verifications @@ -3016,7 +3306,7 @@ ALTER TABLE ONLY public.registrant_verifications -- --- Name: registrars_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: registrars_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.registrars @@ -3024,7 +3314,7 @@ ALTER TABLE ONLY public.registrars -- --- Name: reserved_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: reserved_domains_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.reserved_domains @@ -3032,7 +3322,7 @@ ALTER TABLE ONLY public.reserved_domains -- --- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.settings @@ -3040,7 +3330,7 @@ ALTER TABLE ONLY public.settings -- --- Name: uniq_blocked_domains_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: uniq_blocked_domains_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.blocked_domains @@ -3048,7 +3338,15 @@ ALTER TABLE ONLY public.blocked_domains -- --- Name: uniq_contact_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: uniq_contact_of_type_per_domain; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.domain_contacts + ADD CONSTRAINT uniq_contact_of_type_per_domain UNIQUE (domain_id, type, contact_id); + + +-- +-- Name: uniq_contact_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.contacts @@ -3056,7 +3354,7 @@ ALTER TABLE ONLY public.contacts -- --- Name: uniq_domain_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: uniq_domain_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.domains @@ -3064,7 +3362,15 @@ ALTER TABLE ONLY public.domains -- --- Name: uniq_reserved_domains_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: uniq_hostname_per_domain; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY public.nameservers + ADD CONSTRAINT uniq_hostname_per_domain UNIQUE (domain_id, hostname); + + +-- +-- Name: uniq_reserved_domains_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.reserved_domains @@ -3072,7 +3378,7 @@ ALTER TABLE ONLY public.reserved_domains -- --- Name: uniq_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: uniq_uuid; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.auctions @@ -3080,7 +3386,7 @@ ALTER TABLE ONLY public.auctions -- --- Name: unique_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.registrars @@ -3088,7 +3394,7 @@ ALTER TABLE ONLY public.registrars -- --- Name: unique_contact_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_contact_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.contacts @@ -3096,7 +3402,7 @@ ALTER TABLE ONLY public.contacts -- --- Name: unique_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.registrars @@ -3104,7 +3410,7 @@ ALTER TABLE ONLY public.registrars -- --- Name: unique_number; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_number; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.invoices @@ -3112,7 +3418,7 @@ ALTER TABLE ONLY public.invoices -- --- Name: unique_reference_no; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_reference_no; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.registrars @@ -3120,7 +3426,7 @@ ALTER TABLE ONLY public.registrars -- --- Name: unique_registration_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_registration_code; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.auctions @@ -3128,7 +3434,7 @@ ALTER TABLE ONLY public.auctions -- --- Name: unique_session_id; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_session_id; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.epp_sessions @@ -3136,7 +3442,7 @@ ALTER TABLE ONLY public.epp_sessions -- --- Name: unique_zone_origin; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: unique_zone_origin; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.zones @@ -3144,7 +3450,7 @@ ALTER TABLE ONLY public.zones -- --- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.users @@ -3152,7 +3458,7 @@ ALTER TABLE ONLY public.users -- --- Name: versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: versions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.versions @@ -3160,7 +3466,7 @@ ALTER TABLE ONLY public.versions -- --- Name: white_ips_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: white_ips_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.white_ips @@ -3168,7 +3474,7 @@ ALTER TABLE ONLY public.white_ips -- --- Name: whois_records_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: whois_records_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.whois_records @@ -3176,7 +3482,7 @@ ALTER TABLE ONLY public.whois_records -- --- Name: zones_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- Name: zones_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- ALTER TABLE ONLY public.zones @@ -3184,553 +3490,588 @@ ALTER TABLE ONLY public.zones -- --- Name: index_account_activities_on_account_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_account_activities_on_account_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_account_activities_on_account_id ON public.account_activities USING btree (account_id); -- --- Name: index_account_activities_on_bank_transaction_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_account_activities_on_bank_transaction_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_account_activities_on_bank_transaction_id ON public.account_activities USING btree (bank_transaction_id); -- --- Name: index_account_activities_on_invoice_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_account_activities_on_invoice_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_account_activities_on_invoice_id ON public.account_activities USING btree (invoice_id); -- --- Name: index_accounts_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_accounts_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_accounts_on_registrar_id ON public.accounts USING btree (registrar_id); -- --- Name: index_certificates_on_api_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_certificates_on_api_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_certificates_on_api_user_id ON public.certificates USING btree (api_user_id); -- --- Name: index_contacts_on_code; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_contacts_on_code; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_contacts_on_code ON public.contacts USING btree (code); -- --- Name: index_contacts_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_contacts_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_contacts_on_registrar_id ON public.contacts USING btree (registrar_id); -- --- Name: index_contacts_on_registrar_id_and_ident_type; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_contacts_on_registrar_id_and_ident_type; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_contacts_on_registrar_id_and_ident_type ON public.contacts USING btree (registrar_id, ident_type); -- --- Name: index_directos_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_directos_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_directos_on_item_type_and_item_id ON public.directos USING btree (item_type, item_id); -- --- Name: index_dnskeys_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_dnskeys_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_dnskeys_on_domain_id ON public.dnskeys USING btree (domain_id); -- --- Name: index_dnskeys_on_legacy_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_dnskeys_on_legacy_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_dnskeys_on_legacy_domain_id ON public.dnskeys USING btree (legacy_domain_id); -- --- Name: index_domain_contacts_on_contact_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domain_contacts_on_contact_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domain_contacts_on_contact_id ON public.domain_contacts USING btree (contact_id); -- --- Name: index_domain_contacts_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domain_contacts_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domain_contacts_on_domain_id ON public.domain_contacts USING btree (domain_id); -- --- Name: index_domain_transfers_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domain_transfers_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domain_transfers_on_domain_id ON public.domain_transfers USING btree (domain_id); -- --- Name: index_domains_on_delete_date; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_delete_date; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_delete_date ON public.domains USING btree (delete_date); -- --- Name: index_domains_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE UNIQUE INDEX index_domains_on_name ON public.domains USING btree (name); -- --- Name: index_domains_on_outzone_at; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_outzone_at; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_outzone_at ON public.domains USING btree (outzone_at); -- --- Name: index_domains_on_registrant_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_registrant_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_registrant_id ON public.domains USING btree (registrant_id); -- --- Name: index_domains_on_registrant_verification_asked_at; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_registrant_verification_asked_at; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_registrant_verification_asked_at ON public.domains USING btree (registrant_verification_asked_at); -- --- Name: index_domains_on_registrant_verification_token; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_registrant_verification_token; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_registrant_verification_token ON public.domains USING btree (registrant_verification_token); -- --- Name: index_domains_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_registrar_id ON public.domains USING btree (registrar_id); -- --- Name: index_domains_on_statuses; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_domains_on_statuses; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_domains_on_statuses ON public.domains USING gin (statuses); -- --- Name: index_epp_sessions_on_updated_at; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_email_address_verifications_on_domain; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_email_address_verifications_on_domain ON public.email_address_verifications USING btree (domain); + + +-- +-- Name: index_epp_sessions_on_updated_at; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_epp_sessions_on_updated_at ON public.epp_sessions USING btree (updated_at); -- --- Name: index_invoice_items_on_invoice_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_invoice_items_on_invoice_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_invoice_items_on_invoice_id ON public.invoice_items USING btree (invoice_id); -- --- Name: index_invoices_on_buyer_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_invoices_on_buyer_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_invoices_on_buyer_id ON public.invoices USING btree (buyer_id); -- --- Name: index_legal_documents_on_checksum; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_legal_documents_on_checksum; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_legal_documents_on_checksum ON public.legal_documents USING btree (checksum); -- --- Name: index_legal_documents_on_documentable_type_and_documentable_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_legal_documents_on_documentable_type_and_documentable_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_legal_documents_on_documentable_type_and_documentable_id ON public.legal_documents USING btree (documentable_type, documentable_id); -- --- Name: index_log_account_activities_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_account_activities_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_account_activities_on_item_type_and_item_id ON public.log_account_activities USING btree (item_type, item_id); -- --- Name: index_log_account_activities_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_account_activities_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_account_activities_on_whodunnit ON public.log_account_activities USING btree (whodunnit); -- --- Name: index_log_accounts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_accounts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_accounts_on_item_type_and_item_id ON public.log_accounts USING btree (item_type, item_id); -- --- Name: index_log_accounts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_accounts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_accounts_on_whodunnit ON public.log_accounts USING btree (whodunnit); -- --- Name: index_log_bank_statements_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_bank_statements_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_bank_statements_on_item_type_and_item_id ON public.log_bank_statements USING btree (item_type, item_id); -- --- Name: index_log_bank_statements_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_bank_statements_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_bank_statements_on_whodunnit ON public.log_bank_statements USING btree (whodunnit); -- --- Name: index_log_bank_transactions_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_bank_transactions_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_bank_transactions_on_item_type_and_item_id ON public.log_bank_transactions USING btree (item_type, item_id); -- --- Name: index_log_bank_transactions_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_bank_transactions_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_bank_transactions_on_whodunnit ON public.log_bank_transactions USING btree (whodunnit); -- --- Name: index_log_blocked_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_blocked_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_blocked_domains_on_item_type_and_item_id ON public.log_blocked_domains USING btree (item_type, item_id); -- --- Name: index_log_blocked_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_blocked_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_blocked_domains_on_whodunnit ON public.log_blocked_domains USING btree (whodunnit); -- --- Name: index_log_certificates_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_certificates_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_certificates_on_item_type_and_item_id ON public.log_certificates USING btree (item_type, item_id); -- --- Name: index_log_certificates_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_certificates_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_certificates_on_whodunnit ON public.log_certificates USING btree (whodunnit); -- --- Name: index_log_contacts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_contacts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_contacts_on_item_type_and_item_id ON public.log_contacts USING btree (item_type, item_id); -- --- Name: index_log_contacts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_contacts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_contacts_on_whodunnit ON public.log_contacts USING btree (whodunnit); -- --- Name: index_log_dnskeys_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_dnskeys_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_dnskeys_on_item_type_and_item_id ON public.log_dnskeys USING btree (item_type, item_id); -- --- Name: index_log_dnskeys_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_dnskeys_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_dnskeys_on_whodunnit ON public.log_dnskeys USING btree (whodunnit); -- --- Name: index_log_domain_contacts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_domain_contacts_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_domain_contacts_on_item_type_and_item_id ON public.log_domain_contacts USING btree (item_type, item_id); -- --- Name: index_log_domain_contacts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_domain_contacts_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_domain_contacts_on_whodunnit ON public.log_domain_contacts USING btree (whodunnit); -- --- Name: index_log_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_domains_on_item_type_and_item_id ON public.log_domains USING btree (item_type, item_id); -- --- Name: index_log_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_domains_on_whodunnit ON public.log_domains USING btree (whodunnit); -- --- Name: index_log_invoice_items_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_invoice_items_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_invoice_items_on_item_type_and_item_id ON public.log_invoice_items USING btree (item_type, item_id); -- --- Name: index_log_invoice_items_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_invoice_items_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_invoice_items_on_whodunnit ON public.log_invoice_items USING btree (whodunnit); -- --- Name: index_log_invoices_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_invoices_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_invoices_on_item_type_and_item_id ON public.log_invoices USING btree (item_type, item_id); -- --- Name: index_log_invoices_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_invoices_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_invoices_on_whodunnit ON public.log_invoices USING btree (whodunnit); -- --- Name: index_log_nameservers_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_nameservers_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_nameservers_on_item_type_and_item_id ON public.log_nameservers USING btree (item_type, item_id); -- --- Name: index_log_nameservers_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_nameservers_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_nameservers_on_whodunnit ON public.log_nameservers USING btree (whodunnit); -- --- Name: index_log_notifications_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_notifications_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_notifications_on_item_type_and_item_id ON public.log_notifications USING btree (item_type, item_id); -- --- Name: index_log_notifications_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_notifications_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_notifications_on_whodunnit ON public.log_notifications USING btree (whodunnit); -- --- Name: index_log_registrars_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_registrant_verifications_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_log_registrant_verifications_on_item_type_and_item_id ON public.log_registrant_verifications USING btree (item_type, item_id); + + +-- +-- Name: index_log_registrant_verifications_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_log_registrant_verifications_on_whodunnit ON public.log_registrant_verifications USING btree (whodunnit); + + +-- +-- Name: index_log_registrars_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_registrars_on_item_type_and_item_id ON public.log_registrars USING btree (item_type, item_id); -- --- Name: index_log_registrars_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_registrars_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_registrars_on_whodunnit ON public.log_registrars USING btree (whodunnit); -- --- Name: index_log_reserved_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_reserved_domains_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_reserved_domains_on_item_type_and_item_id ON public.log_reserved_domains USING btree (item_type, item_id); -- --- Name: index_log_reserved_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_reserved_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_reserved_domains_on_whodunnit ON public.log_reserved_domains USING btree (whodunnit); -- --- Name: index_log_settings_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_settings_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_settings_on_item_type_and_item_id ON public.log_settings USING btree (item_type, item_id); -- --- Name: index_log_settings_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_settings_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_settings_on_whodunnit ON public.log_settings USING btree (whodunnit); -- --- Name: index_log_users_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_users_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_users_on_item_type_and_item_id ON public.log_users USING btree (item_type, item_id); -- --- Name: index_log_users_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_log_users_on_whodunnit; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_log_users_on_whodunnit ON public.log_users USING btree (whodunnit); -- --- Name: index_nameservers_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_nameservers_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_nameservers_on_domain_id ON public.nameservers USING btree (domain_id); -- --- Name: index_notifications_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_notifications_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_notifications_on_registrar_id ON public.notifications USING btree (registrar_id); -- --- Name: index_prices_on_zone_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_payment_orders_on_invoice_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_payment_orders_on_invoice_id ON public.payment_orders USING btree (invoice_id); + + +-- +-- Name: index_prices_on_zone_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_prices_on_zone_id ON public.prices USING btree (zone_id); -- --- Name: index_registrant_verifications_on_created_at; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_registrant_verifications_on_created_at; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_registrant_verifications_on_created_at ON public.registrant_verifications USING btree (created_at); -- --- Name: index_registrant_verifications_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_registrant_verifications_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_registrant_verifications_on_domain_id ON public.registrant_verifications USING btree (domain_id); -- --- Name: index_settings_on_thing_type_and_thing_id_and_var; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_settings_on_thing_type_and_thing_id_and_var; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE UNIQUE INDEX index_settings_on_thing_type_and_thing_id_and_var ON public.settings USING btree (thing_type, thing_id, var); -- --- Name: index_users_on_identity_code; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_users_on_identity_code; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_users_on_identity_code ON public.users USING btree (identity_code); -- --- Name: index_users_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_users_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_users_on_registrar_id ON public.users USING btree (registrar_id); -- --- Name: index_versions_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_versions_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_versions_on_item_type_and_item_id ON public.versions USING btree (item_type, item_id); -- --- Name: index_whois_records_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_whois_records_on_domain_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_whois_records_on_domain_id ON public.whois_records USING btree (domain_id); -- --- Name: index_whois_records_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: index_whois_records_on_registrar_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX index_whois_records_on_registrar_id ON public.whois_records USING btree (registrar_id); -- --- Name: log_contacts_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: log_contacts_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX log_contacts_object_legacy_id ON public.log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); -- --- Name: log_dnskeys_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: log_dnskeys_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX log_dnskeys_object_legacy_id ON public.log_contacts USING btree ((((object ->> 'legacy_domain_id'::text))::integer)); -- --- Name: log_domains_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: log_domains_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX log_domains_object_legacy_id ON public.log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); -- --- Name: log_nameservers_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: log_nameservers_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE INDEX log_nameservers_object_legacy_id ON public.log_contacts USING btree ((((object ->> 'legacy_domain_id'::text))::integer)); -- --- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- Name: unique_data_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX unique_data_migrations ON public.data_migrations USING btree (version); + + +-- +-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: -- CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING btree (version); @@ -3904,6 +4245,14 @@ ALTER TABLE ONLY public.registrant_verifications ADD CONSTRAINT fk_rails_f41617a0e9 FOREIGN KEY (domain_id) REFERENCES public.domains(id); +-- +-- Name: fk_rails_f9dc5857c3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_orders + ADD CONSTRAINT fk_rails_f9dc5857c3 FOREIGN KEY (invoice_id) REFERENCES public.invoices(id); + + -- -- Name: invoice_items_invoice_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -3942,801 +4291,427 @@ ALTER TABLE ONLY public.users SET search_path TO "$user",public; -INSERT INTO schema_migrations (version) VALUES ('20140616073945'); +INSERT INTO "schema_migrations" (version) VALUES +('20140616073945'), +('20140620130107'), +('20140627082711'), +('20140701130945'), +('20140702144833'), +('20140702145448'), +('20140724084927'), +('20140730082358'), +('20140730082532'), +('20140730104916'), +('20140730141443'), +('20140731073300'), +('20140731081816'), +('20140801140249'), +('20140804095654'), +('20140808132327'), +('20140813102245'), +('20140813135408'), +('20140815082619'), +('20140815110028'), +('20140815114000'), +('20140819095802'), +('20140819103517'), +('20140822122938'), +('20140826082057'), +('20140826103454'), +('20140827140759'), +('20140828072329'), +('20140828074404'), +('20140828080320'), +('20140828133057'), +('20140902121843'), +('20140911101310'), +('20140911101604'), +('20140925073340'), +('20140925073734'), +('20140925073831'), +('20140925084916'), +('20140925085340'), +('20140925101927'), +('20140926081324'), +('20140926082627'), +('20140926121409'), +('20140929095329'), +('20140930093039'), +('20141001085322'), +('20141006124904'), +('20141006130306'), +('20141008134959'), +('20141009100818'), +('20141009101337'), +('20141010085152'), +('20141010130412'), +('20141014073435'), +('20141015135255'), +('20141015135742'), +('20141105150721'), +('20141111105931'), +('20141114130737'), +('20141120110330'), +('20141120140837'), +('20141121093125'), +('20141124105221'), +('20141125111414'), +('20141126140434'), +('20141127091027'), +('20141202114457'), +('20141203090115'), +('20141210085432'), +('20141211095604'), +('20141215085117'), +('20141216075056'), +('20141216133831'), +('20141218154829'), +('20141229115619'), +('20150105134026'), +('20150109081914'), +('20150110000000'), +('20150110113257'), +('20150122091556'), +('20150122091557'), +('20150128134352'), +('20150129093938'), +('20150129144652'), +('20150130085458'), +('20150130155904'), +('20150130180452'), +('20150130191056'), +('20150200000000'), +('20150202084444'), +('20150202140346'), +('20150203135303'), +('20150212125339'), +('20150213104014'), +('20150217133755'), +('20150217133937'), +('20150223104842'), +('20150226121252'), +('20150226144723'), +('20150227092508'), +('20150227113121'), +('20150302161712'), +('20150303130729'), +('20150303151224'), +('20150305092921'), +('20150318084300'), +('20150318085110'), +('20150318114921'), +('20150319125655'), +('20150320132023'), +('20150330083700'), +('20150402114712'), +('20150407145943'), +('20150408081917'), +('20150410124724'), +('20150410132037'), +('20150413080832'), +('20150413102310'), +('20150413115829'), +('20150413140933'), +('20150414092249'), +('20150414124630'), +('20150414151357'), +('20150415075408'), +('20150416080828'), +('20150416091357'), +('20150416092026'), +('20150416094704'), +('20150417082723'), +('20150421134820'), +('20150422092514'), +('20150422132631'), +('20150422134243'), +('20150423083308'), +('20150427073517'), +('20150428075052'), +('20150429135339'), +('20150430121807'), +('20150504104922'), +('20150504110926'), +('20150505111437'), +('20150511120755'), +('20150512160938'), +('20150513080013'), +('20150514132606'), +('20150515103222'), +('20150518084324'), +('20150519094929'), +('20150519095416'), +('20150519102521'), +('20150519115050'), +('20150519140853'), +('20150519144118'), +('20150520163237'), +('20150520164507'), +('20150521120145'), +('20150522164020'), +('20150525075550'), +('20150601083516'), +('20150601083800'), +('20150603141549'), +('20150603211318'), +('20150603212659'), +('20150609093515'), +('20150609103333'), +('20150610111019'), +('20150610112238'), +('20150610144547'), +('20150611124920'), +('20150612123111'), +('20150612125720'), +('20150701074344'), +('20150703084206'), +('20150703084632'), +('20150706091724'), +('20150707103241'), +('20150707103801'), +('20150707104937'), +('20150707154543'), +('20150709092549'), +('20150713113436'), +('20150722071128'), +('20150803080914'), +('20150810114746'), +('20150810114747'), +('20150825125118'), +('20150827151906'), +('20150903105659'), +('20150910113839'), +('20150915094707'), +('20150921110152'), +('20150921111842'), +('20151028183132'), +('20151029152638'), +('20151112160452'), +('20151117081204'), +('20151120090455'), +('20151124200353'), +('20151125155601'), +('20151127091716'), +('20151130175654'), +('20151202123506'), +('20151209122816'), +('20160106101725'), +('20160108135436'), +('20160113143447'), +('20160118092453'), +('20160118092454'), +('20160218102355'), +('20160225113801'), +('20160225113812'), +('20160226132045'), +('20160226132056'), +('20160304125933'), +('20160311085956'), +('20160311085957'), +('20160405131315'), +('20160411140719'), +('20160414110443'), +('20160421074023'), +('20160429114732'), +('20160527110738'), +('20160629114503'), +('20161004101419'), +('20161227193500'), +('20170221115548'), +('20170419120048'), +('20170420125200'), +('20170422130054'), +('20170422142116'), +('20170422162824'), +('20170423151046'), +('20170423210622'), +('20170423214500'), +('20170423222302'), +('20170423225333'), +('20170424115801'), +('20170506144743'), +('20170506155009'), +('20170506162952'), +('20170506205356'), +('20170506205946'), +('20170506212014'), +('20170509215614'), +('20170604182521'), +('20170606133501'), +('20170606150352'), +('20170606202859'), +('20171009080822'), +('20171009082321'), +('20171025113808'), +('20171025153841'), +('20171121233843'), +('20171123035941'), +('20180112080312'), +('20180112084221'), +('20180112084442'), +('20180120172042'), +('20180120172649'), +('20180120172657'), +('20180120182712'), +('20180120183441'), +('20180121165304'), +('20180122105335'), +('20180123154407'), +('20180123165604'), +('20180123170112'), +('20180125092422'), +('20180126104536'), +('20180126104903'), +('20180129143538'), +('20180129232054'), +('20180129233223'), +('20180206213435'), +('20180206234620'), +('20180207071528'), +('20180207072139'), +('20180211011450'), +('20180211011948'), +('20180212123810'), +('20180212152810'), +('20180212154731'), +('20180213183818'), +('20180214200224'), +('20180214213743'), +('20180218004148'), +('20180228055259'), +('20180228064342'), +('20180228070102'), +('20180228070431'), +('20180228074442'), +('20180306180401'), +('20180306181538'), +('20180306181554'), +('20180306181911'), +('20180306182456'), +('20180306182758'), +('20180306182941'), +('20180306183540'), +('20180306183549'), +('20180308123240'), +('20180309053424'), +('20180309053921'), +('20180309054510'), +('20180310142630'), +('20180313090437'), +('20180313124751'), +('20180314122722'), +('20180327151906'), +('20180331200125'), +('20180422154642'), +('20180612042234'), +('20180612042625'), +('20180612042953'), +('20180613030330'), +('20180613045614'), +('20180713154915'), +('20180801114403'), +('20180808064402'), +('20180816123540'), +('20180823161237'), +('20180823163548'), +('20180823174331'), +('20180823212823'), +('20180824092855'), +('20180824102834'), +('20180824215326'), +('20180825193437'), +('20180825232819'), +('20180826162821'), +('20181001090536'), +('20181002090319'), +('20181017092829'), +('20181017153658'), +('20181017153812'), +('20181017153935'), +('20181017154038'), +('20181017154143'), +('20181017205123'), +('20181022100114'), +('20181108154921'), +('20181129150515'), +('20181212105100'), +('20181212145456'), +('20181212145914'), +('20181213113115'), +('20181217144701'), +('20181217144845'), +('20181220094738'), +('20181220095053'), +('20181223153407'), +('20181226211337'), +('20181227155537'), +('20181227172042'), +('20181230231015'), +('20190102114702'), +('20190102115333'), +('20190102144032'), +('20190209150026'), +('20190302091059'), +('20190302111152'), +('20190311111718'), +('20190312211614'), +('20190315172802'), +('20190319133036'), +('20190322152123'), +('20190322152529'), +('20190328151516'), +('20190328151838'), +('20190415120246'), +('20190426174225'), +('20190506100655'), +('20190510090240'), +('20190510102549'), +('20190515113153'), +('20190516161439'), +('20190520093231'), +('20190617120112'), +('20190617121716'), +('20190617121949'), +('20190617122505'), +('20190620084334'), +('20190811184334'), +('20190811195814'), +('20190811202042'), +('20190811202347'), +('20190811202711'), +('20190811205406'), +('20190917114907'), +('20191004095229'), +('20191004103144'), +('20191004105643'), +('20191004105732'), +('20191004110234'), +('20191004154844'), +('20191005162437'), +('20191007123000'), +('20191008024334'), +('20191024153351'), +('20191024160038'), +('20191203083643'), +('20191206183853'), +('20191212133136'), +('20191227110904'), +('20200113091254'), +('20200115102202'), +('20200130092113'), +('20200203143458'), +('20200204103125'), +('20200311114649'), +('20200417075720'), +('20200421093637'), +('20200505103316'), +('20200505150413'), +('20200518104105'), +('20200529115011'), +('20200605100827'), +('20200610090110'), +('20200630081231'), +('20200714115338'), +('20200807110611'); -INSERT INTO schema_migrations (version) VALUES ('20140620130107'); - -INSERT INTO schema_migrations (version) VALUES ('20140627082711'); - -INSERT INTO schema_migrations (version) VALUES ('20140701130945'); - -INSERT INTO schema_migrations (version) VALUES ('20140702144833'); - -INSERT INTO schema_migrations (version) VALUES ('20140702145448'); - -INSERT INTO schema_migrations (version) VALUES ('20140724084927'); - -INSERT INTO schema_migrations (version) VALUES ('20140730082358'); - -INSERT INTO schema_migrations (version) VALUES ('20140730082532'); - -INSERT INTO schema_migrations (version) VALUES ('20140730104916'); - -INSERT INTO schema_migrations (version) VALUES ('20140730141443'); - -INSERT INTO schema_migrations (version) VALUES ('20140731073300'); - -INSERT INTO schema_migrations (version) VALUES ('20140731081816'); - -INSERT INTO schema_migrations (version) VALUES ('20140801140249'); - -INSERT INTO schema_migrations (version) VALUES ('20140804095654'); - -INSERT INTO schema_migrations (version) VALUES ('20140808132327'); - -INSERT INTO schema_migrations (version) VALUES ('20140813102245'); - -INSERT INTO schema_migrations (version) VALUES ('20140813135408'); - -INSERT INTO schema_migrations (version) VALUES ('20140815082619'); - -INSERT INTO schema_migrations (version) VALUES ('20140815110028'); - -INSERT INTO schema_migrations (version) VALUES ('20140815114000'); - -INSERT INTO schema_migrations (version) VALUES ('20140819095802'); - -INSERT INTO schema_migrations (version) VALUES ('20140819103517'); - -INSERT INTO schema_migrations (version) VALUES ('20140822122938'); - -INSERT INTO schema_migrations (version) VALUES ('20140826082057'); - -INSERT INTO schema_migrations (version) VALUES ('20140826103454'); - -INSERT INTO schema_migrations (version) VALUES ('20140827140759'); - -INSERT INTO schema_migrations (version) VALUES ('20140828072329'); - -INSERT INTO schema_migrations (version) VALUES ('20140828074404'); - -INSERT INTO schema_migrations (version) VALUES ('20140828080320'); - -INSERT INTO schema_migrations (version) VALUES ('20140828133057'); - -INSERT INTO schema_migrations (version) VALUES ('20140902121843'); - -INSERT INTO schema_migrations (version) VALUES ('20140911101310'); - -INSERT INTO schema_migrations (version) VALUES ('20140911101604'); - -INSERT INTO schema_migrations (version) VALUES ('20140925073340'); - -INSERT INTO schema_migrations (version) VALUES ('20140925073734'); - -INSERT INTO schema_migrations (version) VALUES ('20140925073831'); - -INSERT INTO schema_migrations (version) VALUES ('20140925084916'); - -INSERT INTO schema_migrations (version) VALUES ('20140925085340'); - -INSERT INTO schema_migrations (version) VALUES ('20140925101927'); - -INSERT INTO schema_migrations (version) VALUES ('20140926081324'); - -INSERT INTO schema_migrations (version) VALUES ('20140926082627'); - -INSERT INTO schema_migrations (version) VALUES ('20140926121409'); - -INSERT INTO schema_migrations (version) VALUES ('20140929095329'); - -INSERT INTO schema_migrations (version) VALUES ('20140930093039'); - -INSERT INTO schema_migrations (version) VALUES ('20141001085322'); - -INSERT INTO schema_migrations (version) VALUES ('20141006124904'); - -INSERT INTO schema_migrations (version) VALUES ('20141006130306'); - -INSERT INTO schema_migrations (version) VALUES ('20141008134959'); - -INSERT INTO schema_migrations (version) VALUES ('20141009100818'); - -INSERT INTO schema_migrations (version) VALUES ('20141009101337'); - -INSERT INTO schema_migrations (version) VALUES ('20141010085152'); - -INSERT INTO schema_migrations (version) VALUES ('20141010130412'); - -INSERT INTO schema_migrations (version) VALUES ('20141014073435'); - -INSERT INTO schema_migrations (version) VALUES ('20141015135255'); - -INSERT INTO schema_migrations (version) VALUES ('20141015135742'); - -INSERT INTO schema_migrations (version) VALUES ('20141105150721'); - -INSERT INTO schema_migrations (version) VALUES ('20141111105931'); - -INSERT INTO schema_migrations (version) VALUES ('20141114130737'); - -INSERT INTO schema_migrations (version) VALUES ('20141120110330'); - -INSERT INTO schema_migrations (version) VALUES ('20141120140837'); - -INSERT INTO schema_migrations (version) VALUES ('20141121093125'); - -INSERT INTO schema_migrations (version) VALUES ('20141124105221'); - -INSERT INTO schema_migrations (version) VALUES ('20141125111414'); - -INSERT INTO schema_migrations (version) VALUES ('20141126140434'); - -INSERT INTO schema_migrations (version) VALUES ('20141127091027'); - -INSERT INTO schema_migrations (version) VALUES ('20141202114457'); - -INSERT INTO schema_migrations (version) VALUES ('20141203090115'); - -INSERT INTO schema_migrations (version) VALUES ('20141210085432'); - -INSERT INTO schema_migrations (version) VALUES ('20141211095604'); - -INSERT INTO schema_migrations (version) VALUES ('20141215085117'); - -INSERT INTO schema_migrations (version) VALUES ('20141216075056'); - -INSERT INTO schema_migrations (version) VALUES ('20141216133831'); - -INSERT INTO schema_migrations (version) VALUES ('20141218154829'); - -INSERT INTO schema_migrations (version) VALUES ('20141229115619'); - -INSERT INTO schema_migrations (version) VALUES ('20150105134026'); - -INSERT INTO schema_migrations (version) VALUES ('20150109081914'); - -INSERT INTO schema_migrations (version) VALUES ('20150110000000'); - -INSERT INTO schema_migrations (version) VALUES ('20150110113257'); - -INSERT INTO schema_migrations (version) VALUES ('20150122091556'); - -INSERT INTO schema_migrations (version) VALUES ('20150122091557'); - -INSERT INTO schema_migrations (version) VALUES ('20150128134352'); - -INSERT INTO schema_migrations (version) VALUES ('20150129093938'); - -INSERT INTO schema_migrations (version) VALUES ('20150129144652'); - -INSERT INTO schema_migrations (version) VALUES ('20150130085458'); - -INSERT INTO schema_migrations (version) VALUES ('20150130155904'); - -INSERT INTO schema_migrations (version) VALUES ('20150130180452'); - -INSERT INTO schema_migrations (version) VALUES ('20150130191056'); - -INSERT INTO schema_migrations (version) VALUES ('20150200000000'); - -INSERT INTO schema_migrations (version) VALUES ('20150202084444'); - -INSERT INTO schema_migrations (version) VALUES ('20150202140346'); - -INSERT INTO schema_migrations (version) VALUES ('20150203135303'); - -INSERT INTO schema_migrations (version) VALUES ('20150212125339'); - -INSERT INTO schema_migrations (version) VALUES ('20150213104014'); - -INSERT INTO schema_migrations (version) VALUES ('20150217133755'); - -INSERT INTO schema_migrations (version) VALUES ('20150217133937'); - -INSERT INTO schema_migrations (version) VALUES ('20150223104842'); - -INSERT INTO schema_migrations (version) VALUES ('20150226121252'); - -INSERT INTO schema_migrations (version) VALUES ('20150226144723'); - -INSERT INTO schema_migrations (version) VALUES ('20150227092508'); - -INSERT INTO schema_migrations (version) VALUES ('20150227113121'); - -INSERT INTO schema_migrations (version) VALUES ('20150302161712'); - -INSERT INTO schema_migrations (version) VALUES ('20150303130729'); - -INSERT INTO schema_migrations (version) VALUES ('20150303151224'); - -INSERT INTO schema_migrations (version) VALUES ('20150305092921'); - -INSERT INTO schema_migrations (version) VALUES ('20150318084300'); - -INSERT INTO schema_migrations (version) VALUES ('20150318085110'); - -INSERT INTO schema_migrations (version) VALUES ('20150318114921'); - -INSERT INTO schema_migrations (version) VALUES ('20150319125655'); - -INSERT INTO schema_migrations (version) VALUES ('20150320132023'); - -INSERT INTO schema_migrations (version) VALUES ('20150330083700'); - -INSERT INTO schema_migrations (version) VALUES ('20150402114712'); - -INSERT INTO schema_migrations (version) VALUES ('20150407145943'); - -INSERT INTO schema_migrations (version) VALUES ('20150408081917'); - -INSERT INTO schema_migrations (version) VALUES ('20150410124724'); - -INSERT INTO schema_migrations (version) VALUES ('20150410132037'); - -INSERT INTO schema_migrations (version) VALUES ('20150413080832'); - -INSERT INTO schema_migrations (version) VALUES ('20150413102310'); - -INSERT INTO schema_migrations (version) VALUES ('20150413115829'); - -INSERT INTO schema_migrations (version) VALUES ('20150413140933'); - -INSERT INTO schema_migrations (version) VALUES ('20150414092249'); - -INSERT INTO schema_migrations (version) VALUES ('20150414124630'); - -INSERT INTO schema_migrations (version) VALUES ('20150414151357'); - -INSERT INTO schema_migrations (version) VALUES ('20150415075408'); - -INSERT INTO schema_migrations (version) VALUES ('20150416080828'); - -INSERT INTO schema_migrations (version) VALUES ('20150416091357'); - -INSERT INTO schema_migrations (version) VALUES ('20150416092026'); - -INSERT INTO schema_migrations (version) VALUES ('20150416094704'); - -INSERT INTO schema_migrations (version) VALUES ('20150417082723'); - -INSERT INTO schema_migrations (version) VALUES ('20150421134820'); - -INSERT INTO schema_migrations (version) VALUES ('20150422092514'); - -INSERT INTO schema_migrations (version) VALUES ('20150422132631'); - -INSERT INTO schema_migrations (version) VALUES ('20150422134243'); - -INSERT INTO schema_migrations (version) VALUES ('20150423083308'); - -INSERT INTO schema_migrations (version) VALUES ('20150427073517'); - -INSERT INTO schema_migrations (version) VALUES ('20150428075052'); - -INSERT INTO schema_migrations (version) VALUES ('20150429135339'); - -INSERT INTO schema_migrations (version) VALUES ('20150430121807'); - -INSERT INTO schema_migrations (version) VALUES ('20150504104922'); - -INSERT INTO schema_migrations (version) VALUES ('20150504110926'); - -INSERT INTO schema_migrations (version) VALUES ('20150505111437'); - -INSERT INTO schema_migrations (version) VALUES ('20150511120755'); - -INSERT INTO schema_migrations (version) VALUES ('20150512160938'); - -INSERT INTO schema_migrations (version) VALUES ('20150513080013'); - -INSERT INTO schema_migrations (version) VALUES ('20150514132606'); - -INSERT INTO schema_migrations (version) VALUES ('20150515103222'); - -INSERT INTO schema_migrations (version) VALUES ('20150518084324'); - -INSERT INTO schema_migrations (version) VALUES ('20150519094929'); - -INSERT INTO schema_migrations (version) VALUES ('20150519095416'); - -INSERT INTO schema_migrations (version) VALUES ('20150519102521'); - -INSERT INTO schema_migrations (version) VALUES ('20150519115050'); - -INSERT INTO schema_migrations (version) VALUES ('20150519140853'); - -INSERT INTO schema_migrations (version) VALUES ('20150519144118'); - -INSERT INTO schema_migrations (version) VALUES ('20150520163237'); - -INSERT INTO schema_migrations (version) VALUES ('20150520164507'); - -INSERT INTO schema_migrations (version) VALUES ('20150521120145'); - -INSERT INTO schema_migrations (version) VALUES ('20150522164020'); - -INSERT INTO schema_migrations (version) VALUES ('20150525075550'); - -INSERT INTO schema_migrations (version) VALUES ('20150601083516'); - -INSERT INTO schema_migrations (version) VALUES ('20150601083800'); - -INSERT INTO schema_migrations (version) VALUES ('20150603141549'); - -INSERT INTO schema_migrations (version) VALUES ('20150603211318'); - -INSERT INTO schema_migrations (version) VALUES ('20150603212659'); - -INSERT INTO schema_migrations (version) VALUES ('20150609093515'); - -INSERT INTO schema_migrations (version) VALUES ('20150609103333'); - -INSERT INTO schema_migrations (version) VALUES ('20150610111019'); - -INSERT INTO schema_migrations (version) VALUES ('20150610112238'); - -INSERT INTO schema_migrations (version) VALUES ('20150610144547'); - -INSERT INTO schema_migrations (version) VALUES ('20150611124920'); - -INSERT INTO schema_migrations (version) VALUES ('20150612123111'); - -INSERT INTO schema_migrations (version) VALUES ('20150612125720'); - -INSERT INTO schema_migrations (version) VALUES ('20150701074344'); - -INSERT INTO schema_migrations (version) VALUES ('20150703084206'); - -INSERT INTO schema_migrations (version) VALUES ('20150703084632'); - -INSERT INTO schema_migrations (version) VALUES ('20150706091724'); - -INSERT INTO schema_migrations (version) VALUES ('20150707103241'); - -INSERT INTO schema_migrations (version) VALUES ('20150707103801'); - -INSERT INTO schema_migrations (version) VALUES ('20150707104937'); - -INSERT INTO schema_migrations (version) VALUES ('20150707154543'); - -INSERT INTO schema_migrations (version) VALUES ('20150709092549'); - -INSERT INTO schema_migrations (version) VALUES ('20150713113436'); - -INSERT INTO schema_migrations (version) VALUES ('20150722071128'); - -INSERT INTO schema_migrations (version) VALUES ('20150803080914'); - -INSERT INTO schema_migrations (version) VALUES ('20150810114746'); - -INSERT INTO schema_migrations (version) VALUES ('20150810114747'); - -INSERT INTO schema_migrations (version) VALUES ('20150825125118'); - -INSERT INTO schema_migrations (version) VALUES ('20150827151906'); - -INSERT INTO schema_migrations (version) VALUES ('20150903105659'); - -INSERT INTO schema_migrations (version) VALUES ('20150910113839'); - -INSERT INTO schema_migrations (version) VALUES ('20150915094707'); - -INSERT INTO schema_migrations (version) VALUES ('20150921110152'); - -INSERT INTO schema_migrations (version) VALUES ('20150921111842'); - -INSERT INTO schema_migrations (version) VALUES ('20151028183132'); - -INSERT INTO schema_migrations (version) VALUES ('20151029152638'); - -INSERT INTO schema_migrations (version) VALUES ('20151112160452'); - -INSERT INTO schema_migrations (version) VALUES ('20151117081204'); - -INSERT INTO schema_migrations (version) VALUES ('20151120090455'); - -INSERT INTO schema_migrations (version) VALUES ('20151124200353'); - -INSERT INTO schema_migrations (version) VALUES ('20151125155601'); - -INSERT INTO schema_migrations (version) VALUES ('20151127091716'); - -INSERT INTO schema_migrations (version) VALUES ('20151130175654'); - -INSERT INTO schema_migrations (version) VALUES ('20151202123506'); - -INSERT INTO schema_migrations (version) VALUES ('20151209122816'); - -INSERT INTO schema_migrations (version) VALUES ('20160106101725'); - -INSERT INTO schema_migrations (version) VALUES ('20160108135436'); - -INSERT INTO schema_migrations (version) VALUES ('20160113143447'); - -INSERT INTO schema_migrations (version) VALUES ('20160118092453'); - -INSERT INTO schema_migrations (version) VALUES ('20160118092454'); - -INSERT INTO schema_migrations (version) VALUES ('20160218102355'); - -INSERT INTO schema_migrations (version) VALUES ('20160225113801'); - -INSERT INTO schema_migrations (version) VALUES ('20160225113812'); - -INSERT INTO schema_migrations (version) VALUES ('20160226132045'); - -INSERT INTO schema_migrations (version) VALUES ('20160226132056'); - -INSERT INTO schema_migrations (version) VALUES ('20160304125933'); - -INSERT INTO schema_migrations (version) VALUES ('20160311085956'); - -INSERT INTO schema_migrations (version) VALUES ('20160311085957'); - -INSERT INTO schema_migrations (version) VALUES ('20160405131315'); - -INSERT INTO schema_migrations (version) VALUES ('20160411140719'); - -INSERT INTO schema_migrations (version) VALUES ('20160414110443'); - -INSERT INTO schema_migrations (version) VALUES ('20160421074023'); - -INSERT INTO schema_migrations (version) VALUES ('20160429114732'); - -INSERT INTO schema_migrations (version) VALUES ('20160527110738'); - -INSERT INTO schema_migrations (version) VALUES ('20160629114503'); - -INSERT INTO schema_migrations (version) VALUES ('20161004101419'); - -INSERT INTO schema_migrations (version) VALUES ('20161227193500'); - -INSERT INTO schema_migrations (version) VALUES ('20170221115548'); - -INSERT INTO schema_migrations (version) VALUES ('20170419120048'); - -INSERT INTO schema_migrations (version) VALUES ('20170420125200'); - -INSERT INTO schema_migrations (version) VALUES ('20170422130054'); - -INSERT INTO schema_migrations (version) VALUES ('20170422142116'); - -INSERT INTO schema_migrations (version) VALUES ('20170422162824'); - -INSERT INTO schema_migrations (version) VALUES ('20170423151046'); - -INSERT INTO schema_migrations (version) VALUES ('20170423210622'); - -INSERT INTO schema_migrations (version) VALUES ('20170423214500'); - -INSERT INTO schema_migrations (version) VALUES ('20170423222302'); - -INSERT INTO schema_migrations (version) VALUES ('20170423225333'); - -INSERT INTO schema_migrations (version) VALUES ('20170424115801'); - -INSERT INTO schema_migrations (version) VALUES ('20170506144743'); - -INSERT INTO schema_migrations (version) VALUES ('20170506155009'); - -INSERT INTO schema_migrations (version) VALUES ('20170506162952'); - -INSERT INTO schema_migrations (version) VALUES ('20170506205356'); - -INSERT INTO schema_migrations (version) VALUES ('20170506205946'); - -INSERT INTO schema_migrations (version) VALUES ('20170506212014'); - -INSERT INTO schema_migrations (version) VALUES ('20170509215614'); - -INSERT INTO schema_migrations (version) VALUES ('20170604182521'); - -INSERT INTO schema_migrations (version) VALUES ('20170606133501'); - -INSERT INTO schema_migrations (version) VALUES ('20170606150352'); - -INSERT INTO schema_migrations (version) VALUES ('20170606202859'); - -INSERT INTO schema_migrations (version) VALUES ('20171009080822'); - -INSERT INTO schema_migrations (version) VALUES ('20171009082321'); - -INSERT INTO schema_migrations (version) VALUES ('20171025113808'); - -INSERT INTO schema_migrations (version) VALUES ('20171025153841'); - -INSERT INTO schema_migrations (version) VALUES ('20171121233843'); - -INSERT INTO schema_migrations (version) VALUES ('20171123035941'); - -INSERT INTO schema_migrations (version) VALUES ('20180112080312'); - -INSERT INTO schema_migrations (version) VALUES ('20180112084221'); - -INSERT INTO schema_migrations (version) VALUES ('20180112084442'); - -INSERT INTO schema_migrations (version) VALUES ('20180120172042'); - -INSERT INTO schema_migrations (version) VALUES ('20180120172649'); - -INSERT INTO schema_migrations (version) VALUES ('20180120172657'); - -INSERT INTO schema_migrations (version) VALUES ('20180120182712'); - -INSERT INTO schema_migrations (version) VALUES ('20180120183441'); - -INSERT INTO schema_migrations (version) VALUES ('20180121165304'); - -INSERT INTO schema_migrations (version) VALUES ('20180122105335'); - -INSERT INTO schema_migrations (version) VALUES ('20180123154407'); - -INSERT INTO schema_migrations (version) VALUES ('20180123165604'); - -INSERT INTO schema_migrations (version) VALUES ('20180123170112'); - -INSERT INTO schema_migrations (version) VALUES ('20180125092422'); - -INSERT INTO schema_migrations (version) VALUES ('20180126104536'); - -INSERT INTO schema_migrations (version) VALUES ('20180126104903'); - -INSERT INTO schema_migrations (version) VALUES ('20180129143538'); - -INSERT INTO schema_migrations (version) VALUES ('20180129232054'); - -INSERT INTO schema_migrations (version) VALUES ('20180129233223'); - -INSERT INTO schema_migrations (version) VALUES ('20180206213435'); - -INSERT INTO schema_migrations (version) VALUES ('20180206234620'); - -INSERT INTO schema_migrations (version) VALUES ('20180207071528'); - -INSERT INTO schema_migrations (version) VALUES ('20180207072139'); - -INSERT INTO schema_migrations (version) VALUES ('20180211011450'); - -INSERT INTO schema_migrations (version) VALUES ('20180211011948'); - -INSERT INTO schema_migrations (version) VALUES ('20180212123810'); - -INSERT INTO schema_migrations (version) VALUES ('20180212152810'); - -INSERT INTO schema_migrations (version) VALUES ('20180212154731'); - -INSERT INTO schema_migrations (version) VALUES ('20180213183818'); - -INSERT INTO schema_migrations (version) VALUES ('20180214200224'); - -INSERT INTO schema_migrations (version) VALUES ('20180214213743'); - -INSERT INTO schema_migrations (version) VALUES ('20180218004148'); - -INSERT INTO schema_migrations (version) VALUES ('20180228055259'); - -INSERT INTO schema_migrations (version) VALUES ('20180228064342'); - -INSERT INTO schema_migrations (version) VALUES ('20180228070102'); - -INSERT INTO schema_migrations (version) VALUES ('20180228070431'); - -INSERT INTO schema_migrations (version) VALUES ('20180228074442'); - -INSERT INTO schema_migrations (version) VALUES ('20180306180401'); - -INSERT INTO schema_migrations (version) VALUES ('20180306181538'); - -INSERT INTO schema_migrations (version) VALUES ('20180306181554'); - -INSERT INTO schema_migrations (version) VALUES ('20180306181911'); - -INSERT INTO schema_migrations (version) VALUES ('20180306182456'); - -INSERT INTO schema_migrations (version) VALUES ('20180306182758'); - -INSERT INTO schema_migrations (version) VALUES ('20180306182941'); - -INSERT INTO schema_migrations (version) VALUES ('20180306183540'); - -INSERT INTO schema_migrations (version) VALUES ('20180306183549'); - -INSERT INTO schema_migrations (version) VALUES ('20180308123240'); - -INSERT INTO schema_migrations (version) VALUES ('20180309053424'); - -INSERT INTO schema_migrations (version) VALUES ('20180309053921'); - -INSERT INTO schema_migrations (version) VALUES ('20180309054510'); - -INSERT INTO schema_migrations (version) VALUES ('20180310142630'); - -INSERT INTO schema_migrations (version) VALUES ('20180313090437'); - -INSERT INTO schema_migrations (version) VALUES ('20180313124751'); - -INSERT INTO schema_migrations (version) VALUES ('20180314122722'); - -INSERT INTO schema_migrations (version) VALUES ('20180327151906'); - -INSERT INTO schema_migrations (version) VALUES ('20180331200125'); - -INSERT INTO schema_migrations (version) VALUES ('20180422154642'); - -INSERT INTO schema_migrations (version) VALUES ('20180612042234'); - -INSERT INTO schema_migrations (version) VALUES ('20180612042625'); - -INSERT INTO schema_migrations (version) VALUES ('20180612042953'); - -INSERT INTO schema_migrations (version) VALUES ('20180613030330'); - -INSERT INTO schema_migrations (version) VALUES ('20180613045614'); - -INSERT INTO schema_migrations (version) VALUES ('20180713154915'); - -INSERT INTO schema_migrations (version) VALUES ('20180808064402'); - -INSERT INTO schema_migrations (version) VALUES ('20180816123540'); - -INSERT INTO schema_migrations (version) VALUES ('20180823161237'); - -INSERT INTO schema_migrations (version) VALUES ('20180823163548'); - -INSERT INTO schema_migrations (version) VALUES ('20180823174331'); - -INSERT INTO schema_migrations (version) VALUES ('20180823212823'); - -INSERT INTO schema_migrations (version) VALUES ('20180824092855'); - -INSERT INTO schema_migrations (version) VALUES ('20180824102834'); - -INSERT INTO schema_migrations (version) VALUES ('20180824215326'); - -INSERT INTO schema_migrations (version) VALUES ('20180825193437'); - -INSERT INTO schema_migrations (version) VALUES ('20180825232819'); - -INSERT INTO schema_migrations (version) VALUES ('20180826162821'); - -INSERT INTO schema_migrations (version) VALUES ('20181001090536'); - -INSERT INTO schema_migrations (version) VALUES ('20181002090319'); - -INSERT INTO schema_migrations (version) VALUES ('20181017092829'); - -INSERT INTO schema_migrations (version) VALUES ('20181017153658'); - -INSERT INTO schema_migrations (version) VALUES ('20181017153812'); - -INSERT INTO schema_migrations (version) VALUES ('20181017153935'); - -INSERT INTO schema_migrations (version) VALUES ('20181017154038'); - -INSERT INTO schema_migrations (version) VALUES ('20181017154143'); - -INSERT INTO schema_migrations (version) VALUES ('20181017205123'); - -INSERT INTO schema_migrations (version) VALUES ('20181022100114'); - -INSERT INTO schema_migrations (version) VALUES ('20181108154921'); - -INSERT INTO schema_migrations (version) VALUES ('20181129150515'); - -INSERT INTO schema_migrations (version) VALUES ('20181212105100'); - -INSERT INTO schema_migrations (version) VALUES ('20181212145456'); - -INSERT INTO schema_migrations (version) VALUES ('20181212145914'); - -INSERT INTO schema_migrations (version) VALUES ('20181213113115'); - -INSERT INTO schema_migrations (version) VALUES ('20181217144701'); - -INSERT INTO schema_migrations (version) VALUES ('20181217144845'); - -INSERT INTO schema_migrations (version) VALUES ('20181220094738'); - -INSERT INTO schema_migrations (version) VALUES ('20181220095053'); - -INSERT INTO schema_migrations (version) VALUES ('20181223153407'); - -INSERT INTO schema_migrations (version) VALUES ('20181226211337'); - -INSERT INTO schema_migrations (version) VALUES ('20181227155537'); - -INSERT INTO schema_migrations (version) VALUES ('20181227172042'); - -INSERT INTO schema_migrations (version) VALUES ('20181230231015'); - -INSERT INTO schema_migrations (version) VALUES ('20190102114702'); - -INSERT INTO schema_migrations (version) VALUES ('20190102115333'); - -INSERT INTO schema_migrations (version) VALUES ('20190102144032'); - -INSERT INTO schema_migrations (version) VALUES ('20190209150026'); - -INSERT INTO schema_migrations (version) VALUES ('20190302091059'); - -INSERT INTO schema_migrations (version) VALUES ('20190302111152'); - -INSERT INTO schema_migrations (version) VALUES ('20190311111718'); - -INSERT INTO schema_migrations (version) VALUES ('20190312211614'); - -INSERT INTO schema_migrations (version) VALUES ('20190315172802'); - -INSERT INTO schema_migrations (version) VALUES ('20190319133036'); - -INSERT INTO schema_migrations (version) VALUES ('20190322152123'); - -INSERT INTO schema_migrations (version) VALUES ('20190322152529'); - -INSERT INTO schema_migrations (version) VALUES ('20190328151516'); - -INSERT INTO schema_migrations (version) VALUES ('20190328151838'); - -INSERT INTO schema_migrations (version) VALUES ('20190415120246'); - -INSERT INTO schema_migrations (version) VALUES ('20190426174225'); - -INSERT INTO schema_migrations (version) VALUES ('20190506100655'); - -INSERT INTO schema_migrations (version) VALUES ('20190510090240'); - -INSERT INTO schema_migrations (version) VALUES ('20190510102549'); - -INSERT INTO schema_migrations (version) VALUES ('20190515113153'); - -INSERT INTO schema_migrations (version) VALUES ('20190516161439'); - -INSERT INTO schema_migrations (version) VALUES ('20190520093231'); - -INSERT INTO schema_migrations (version) VALUES ('20190617120112'); - -INSERT INTO schema_migrations (version) VALUES ('20190617121716'); - -INSERT INTO schema_migrations (version) VALUES ('20190617121949'); - -INSERT INTO schema_migrations (version) VALUES ('20190617122505'); - -INSERT INTO schema_migrations (version) VALUES ('20190620084334'); - -INSERT INTO schema_migrations (version) VALUES ('20190811184334'); - -INSERT INTO schema_migrations (version) VALUES ('20190811195814'); - -INSERT INTO schema_migrations (version) VALUES ('20190811202042'); - -INSERT INTO schema_migrations (version) VALUES ('20190811202347'); - -INSERT INTO schema_migrations (version) VALUES ('20190811202711'); - -INSERT INTO schema_migrations (version) VALUES ('20190811205406'); - -INSERT INTO schema_migrations (version) VALUES ('20190917114907'); - -INSERT INTO schema_migrations (version) VALUES ('20191004095229'); - -INSERT INTO schema_migrations (version) VALUES ('20191004103144'); - -INSERT INTO schema_migrations (version) VALUES ('20191004105643'); - -INSERT INTO schema_migrations (version) VALUES ('20191004105732'); - -INSERT INTO schema_migrations (version) VALUES ('20191004110234'); - -INSERT INTO schema_migrations (version) VALUES ('20191004154844'); - -INSERT INTO schema_migrations (version) VALUES ('20191005162437'); - -INSERT INTO schema_migrations (version) VALUES ('20191007123000'); - -INSERT INTO schema_migrations (version) VALUES ('20191008024334'); - -INSERT INTO schema_migrations (version) VALUES ('20191024153351'); - -INSERT INTO schema_migrations (version) VALUES ('20191024160038'); diff --git a/db/whois_schema.rb b/db/whois_schema.rb index 7d3756dc1..9353bd80c 100644 --- a/db/whois_schema.rb +++ b/db/whois_schema.rb @@ -1,4 +1,3 @@ -# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. @@ -11,41 +10,33 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20181102124618) do +ActiveRecord::Schema.define(version: 2018_11_02_124618) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" - create_table "ar_internal_metadata", primary_key: "key", force: :cascade do |t| - t.string "value" + create_table "contact_requests", force: :cascade do |t| + t.integer "whois_record_id", null: false + t.string "secret", null: false + t.string "email", null: false + t.string "name", null: false + t.datetime "valid_to", null: false + t.string "status", default: "new", null: false + t.inet "ip_address" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["email"], name: "index_contact_requests_on_email" + t.index ["ip_address"], name: "index_contact_requests_on_ip_address" + t.index ["secret"], name: "index_contact_requests_on_secret", unique: true + t.index ["whois_record_id"], name: "index_contact_requests_on_whois_record_id" end - create_table "contact_requests", id: :bigserial, force: :cascade do |t| - t.integer "whois_record_id", null: false - t.string "secret", null: false - t.string "email", null: false - t.string "name", null: false - t.datetime "valid_to", null: false - t.string "status", default: "new", null: false - t.inet "ip_address" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - add_index "contact_requests", ["email"], name: "index_contact_requests_on_email", using: :btree - add_index "contact_requests", ["ip_address"], name: "index_contact_requests_on_ip_address", using: :btree - add_index "contact_requests", ["secret"], name: "index_contact_requests_on_secret", unique: true, using: :btree - add_index "contact_requests", ["whois_record_id"], name: "index_contact_requests_on_whois_record_id", using: :btree - create_table "whois_records", force: :cascade do |t| - t.string "name" - t.json "json" + t.string "name" + t.json "json" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["name"], name: "index_domains_on_name" end - add_index "whois_records", ["name"], name: "index_domains_on_name", using: :btree - end diff --git a/doc/registrant-api/v1/domain.md b/doc/registrant-api/v1/domain.md index 5a5a61366..9163a2850 100644 --- a/doc/registrant-api/v1/domain.md +++ b/doc/registrant-api/v1/domain.md @@ -34,21 +34,25 @@ Content-Type: application/json "admin_contacts":[ { "name":"John Smith", - "id":"62015e7d-42c8-4d68-8164-e9b71680fd95" + "id":"62015e7d-42c8-4d68-8164-e9b71680fd95", + "email": "john@email.com" }, { "name":"William Smith", - "id":"a041c5b6-7772-4fac-83cd-fbce3b2c8867" + "id":"a041c5b6-7772-4fac-83cd-fbce3b2c8867", + "email": "william@email.com" } ], "tech_contacts":[ { "name":"John Smith", - "id":"62015e7d-42c8-4d68-8164-e9b71680fd95" + "id":"62015e7d-42c8-4d68-8164-e9b71680fd95", + "email": "john@email.com" }, { "name":"William Smith", "id":"a041c5b6-7772-4fac-83cd-fbce3b2c8867" + "email": "william@email.com" } ], "transfer_code":"98oiewslkfkd", @@ -60,9 +64,6 @@ Content-Type: application/json "period_unit":"y", "creator_str":null, "updator_str":null, - "legacy_id":null, - "legacy_registrar_id":null, - "legacy_registrant_id":null, "outzone_at":"2016-09-24T09:11:14.861Z", "delete_date":"2016-10-24", "registrant_verification_asked_at":null, @@ -96,6 +97,10 @@ Content-Type: application/json }, ], + "dnssec_keys": [ + "257 3 13 KlHFYV42UtxC7LpsolDpoUZ9DNPDRYQypalBRIqlubBg/zg78aqciLk+NaWUbrkN7AUaM7h7tx91sLN+ORVPxA==", + ], + "dnssec_changed_at": "2015-09-09T09:11:14.860Z", "status_notes":{ }, @@ -175,9 +180,6 @@ Content-Type: application/json "period_unit":"y", "creator_str":null, "updator_str":null, - "legacy_id":null, - "legacy_registrar_id":null, - "legacy_registrant_id":null, "outzone_at":"2016-09-24T09:11:14.861Z", "delete_date":"2016-10-24", "registrant_verification_asked_at":null, @@ -211,6 +213,10 @@ Content-Type: application/json }, ], + "dnssec_keys": [ + "257 3 13 KlHFYV42UtxC7LpsolDpoUZ9DNPDRYQypalBRIqlubBg/zg78aqciLk+NaWUbrkN7AUaM7h7tx91sLN+ORVPxA==", + ], + "dnssec_changed_at": "2015-09-09T09:11:14.860Z", "status_notes":{ }, @@ -282,9 +288,6 @@ Content-Type: application/json "period_unit":"y", "creator_str":null, "updator_str":null, - "legacy_id":null, - "legacy_registrar_id":null, - "legacy_registrant_id":null, "outzone_at":"2016-09-24T09:11:14.861Z", "delete_date":"2016-10-24", "registrant_verification_asked_at":null, @@ -317,6 +320,10 @@ Content-Type: application/json ] } ], + "dnssec_keys": [ + "257 3 13 KlHFYV42UtxC7LpsolDpoUZ9DNPDRYQypalBRIqlubBg/zg78aqciLk+NaWUbrkN7AUaM7h7tx91sLN+ORVPxA==", + ], + "dnssec_changed_at": "2015-09-09T09:11:14.860Z", "status_notes":{ }, diff --git a/doc/registrant-api/v1/registry_lock.md b/doc/registrant-api/v1/registry_lock.md index 61a2c0839..17f4c6f6e 100644 --- a/doc/registrant-api/v1/registry_lock.md +++ b/doc/registrant-api/v1/registry_lock.md @@ -60,9 +60,6 @@ Content-Type: application/json "period_unit":"y", "creator_str":null, "updator_str":null, - "legacy_id":null, - "legacy_registrar_id":null, - "legacy_registrant_id":null, "outzone_at":"2016-09-24T09:11:14.861Z", "delete_date":"2016-10-24", "registrant_verification_asked_at":null, @@ -204,9 +201,6 @@ Content-Type: application/json "period_unit":"y", "creator_str":null, "updator_str":null, - "legacy_id":null, - "legacy_registrar_id":null, - "legacy_registrant_id":null, "outzone_at":"2016-09-24T09:11:14.861Z", "delete_date":"2016-10-24", "registrant_verification_asked_at":null, diff --git a/doc/repp/v1/auctions.md b/doc/repp/v1/auctions.md new file mode 100644 index 000000000..727e6712e --- /dev/null +++ b/doc/repp/v1/auctions.md @@ -0,0 +1,39 @@ +## GET /repp/v1/auctions + +Return a list of auctions currently in progress. The list of domains changes +every day. + +In contrast with other endpoints in REPP, this one is publicly available for +anyone without authentication. + +#### Request + +``` +GET /repp/v1/auctions HTTP/1.1 +Host: registry.test +User-Agent: curl/7.64.1 +Accept: */* +``` + +#### Response + +``` +HTTP/1.1 200 OK +Date: Thu, 21 May 2020 10:39:45 GMT +Content-Type: application/json; charset=utf-8 +ETag: W/"217bd9ee4dfbb332172a1baf80ee0ba9" +Cache-Control: max-age=0, private, must-revalidate +X-Request-Id: a26b6801-bf3f-4922-b0db-3b081bacb130 +X-Runtime: 1.481174 +Transfer-Encoding: chunked + +{ + "count":1, + "auctions": [ + { + "domain_name": "auctionäöüõ.test", + "punycode_domain_name": "xn--auction-cxa7mj0e.test" + } + ] +} +``` diff --git a/doc/repp/v1/contact.md b/doc/repp/v1/contact.md index 71bf6276d..41f45551f 100644 --- a/doc/repp/v1/contact.md +++ b/doc/repp/v1/contact.md @@ -50,7 +50,6 @@ Content-Type: application/json "zip": "11111", "country_code": "EE", "state": null, - "legacy_id": null, "statuses": [ "ok" ], diff --git a/doc/repp/v1/domain.md b/doc/repp/v1/domain.md index 035bb1e9a..c6734cbe2 100644 --- a/doc/repp/v1/domain.md +++ b/doc/repp/v1/domain.md @@ -48,9 +48,6 @@ Content-Type: application/json "period_unit": "y", "creator_str": null, "updator_str": null, - "legacy_id": null, - "legacy_registrar_id": null, - "legacy_registrant_id": null, "outzone_at": "2016-09-24T09:11:14.861Z", "delete_date": "2016-10-24", "registrant_verification_asked_at": null, diff --git a/doc/repp/v1/retained_domains.md b/doc/repp/v1/retained_domains.md new file mode 100644 index 000000000..7484ff8f2 --- /dev/null +++ b/doc/repp/v1/retained_domains.md @@ -0,0 +1,100 @@ +## GET /repp/v1/retained_domains + +Return a list of disputed, reserved and blocked domains, along with total count. +You can filter them by type of the domain, which can be: `reserved`, `blocked` +or `disputed`. + +NB! A domain name can be both `disputed` and `reserved` at the same time, and it +will appear on the list as two separate objects. + +In contrast with other endpoints in REPP, this one is publicly available for +anyone without authentication. + +#### Parameters + +| Field name | Required | Type | Allowed values | Description | +| ---------- | -------- | ---- | -------------- | ----------- | +| type | false | string | ["reserved", "blocked", "disputed"] | Type of domains to show | + + +#### Request + +``` +GET /repp/v1/retained_domains?type=reserved HTTP/1.1 +Accept: application/json +User-Agent: curl/7.64.1 +``` + +#### Response + +``` +HTTP/1.1 200 OK +Date: Fri, 15 May 2020 11:30:07 GMT +Content-Type: application/json; charset=utf-8 +ETag: W/"a905b531243a6b0be42beb9d6ce60619" +Cache-Control: max-age=0, private, must-revalidate +Transfer-Encoding: chunked + +{ + "count": 1, + "domains": [ + { + "name": "reserved.test", + "status": "reserved", + "punycode_name": "reserved.test" + } + ] +} +``` + +After you have made the first request, you can save the ETag header, and +send it as If-None-Match in the subsequent request for cache validation. +Due to the fact that the lists are not changing frequently and are quite long, +it is recommended that you take advantage of ETag cache. + +ETag key values depend on the request parameters. A request for only blocked +domains returns different cache key than request for all domains. + +### Cache Request + +``` +GET /repp/v1/retained_domains?type=reserved HTTP/1.1 +Accept: application/json +User-Agent: curl/7.64.1 +If-None-Match: W/"a905b531243a6b0be42beb9d6ce60619" +``` + +#### Cache hit response + +Response with no body and status 304 is sent in case the list have not changed. + +``` +HTTP/1.1 304 Not Modified +Date: Fri, 15 May 2020 11:34:25 GMT +ETag: W/"a905b531243a6b0be42beb9d6ce60619" +Cache-Control: max-age=0, private, must-revalidate +``` + +#### Cache miss response + +Standard 200 response (with the current complete list) is sent when the list have changed since last requested. + + +``` +HTTP/1.1 200 OK +Date: Fri, 15 May 2020 11:30:07 GMT +Content-Type: application/json; charset=utf-8 +ETag: W/"a905b531243a6b0be42beb9d6ce60619" +Transfer-Encoding: chunked + +{ + "count": 1, + "domains": [ + { + "name": "reserved.test", + "status": "reserved", + "punycode_name": "reserved.test" + } + ] +} +``` diff --git a/doc/repp_doc.md b/doc/repp_doc.md index f01484fc3..1ffbf669c 100644 --- a/doc/repp_doc.md +++ b/doc/repp_doc.md @@ -1,7 +1,7 @@ # REPP integration specification -REPP uses HTTP/1.1 protocol (http://tools.ietf.org/html/rfc2616) and -Basic Authentication (http://tools.ietf.org/html/rfc2617#section-2) using +REPP uses HTTP/1.1 protocol (http://tools.ietf.org/html/rfc2616) and +Basic Authentication (http://tools.ietf.org/html/rfc2617#section-2) using Secure Transport (https://tools.ietf.org/html/rfc5246) with certificate and key (https://tools.ietf.org/html/rfc5280). Credentials and certificate are issued by EIS (in an exchange for desired API username, CSR and IP). @@ -10,13 +10,15 @@ To quickly test the API, use curl: curl -q -k --cert user.crt.pem --key user.key.pem https://TBA/repp/v1/accounts/balance -u username:password -Test API endpoint: https://testepp.internet.ee/repp/v1 +Test API endpoint: https://testepp.internet.ee/repp/v1 Production API endpoint: TBA Main communication specification through Restful EPP (REPP): -[Contact related functions](repp/v1/contact.md) -[Domain related functions](repp/v1/domain.md) -[Domain transfers](repp/v1/domain_transfers.md) -[Account related functions](repp/v1/account.md) -[Nameservers](repp/v1/nameservers.md) +[Contact related functions](repp/v1/contact.md) +[Domain related functions](repp/v1/domain.md) +[Domain transfers](repp/v1/domain_transfers.md) +[Account related functions](repp/v1/account.md) +[Nameservers](repp/v1/nameservers.md) +[Retained domains](repp/v1/retained_domains.md) +[Auctions](repp/v1/auctions.md) diff --git a/lib/action_controller/api.rb b/lib/action_controller/api.rb deleted file mode 100644 index 5a9fd4512..000000000 --- a/lib/action_controller/api.rb +++ /dev/null @@ -1,149 +0,0 @@ -# frozen_string_literal: true - -require "action_view" -require "action_controller" -require "action_controller/log_subscriber" - -module ActionController - # API Controller is a lightweight version of ActionController::Base, - # created for applications that don't require all functionalities that a complete - # \Rails controller provides, allowing you to create controllers with just the - # features that you need for API only applications. - # - # An API Controller is different from a normal controller in the sense that - # by default it doesn't include a number of features that are usually required - # by browser access only: layouts and templates rendering, cookies, sessions, - # flash, assets, and so on. This makes the entire controller stack thinner, - # suitable for API applications. It doesn't mean you won't have such - # features if you need them: they're all available for you to include in - # your application, they're just not part of the default API controller stack. - # - # Normally, +ApplicationController+ is the only controller that inherits from - # ActionController::API. All other controllers in turn inherit from - # +ApplicationController+. - # - # A sample controller could look like this: - # - # class PostsController < ApplicationController - # def index - # posts = Post.all - # render json: posts - # end - # end - # - # Request, response, and parameters objects all work the exact same way as - # ActionController::Base. - # - # == Renders - # - # The default API Controller stack includes all renderers, which means you - # can use render :json and brothers freely in your controllers. Keep - # in mind that templates are not going to be rendered, so you need to ensure - # your controller is calling either render or redirect_to in - # all actions, otherwise it will return 204 No Content. - # - # def show - # post = Post.find(params[:id]) - # render json: post - # end - # - # == Redirects - # - # Redirects are used to move from one action to another. You can use the - # redirect_to method in your controllers in the same way as in - # ActionController::Base. For example: - # - # def create - # redirect_to root_url and return if not_authorized? - # # do stuff here - # end - # - # == Adding New Behavior - # - # In some scenarios you may want to add back some functionality provided by - # ActionController::Base that is not present by default in - # ActionController::API, for instance MimeResponds. This - # module gives you the respond_to method. Adding it is quite simple, - # you just need to include the module in a specific controller or in - # +ApplicationController+ in case you want it available in your entire - # application: - # - # class ApplicationController < ActionController::API - # include ActionController::MimeResponds - # end - # - # class PostsController < ApplicationController - # def index - # posts = Post.all - # - # respond_to do |format| - # format.json { render json: posts } - # format.xml { render xml: posts } - # end - # end - # end - # - # Make sure to check the modules included in ActionController::Base - # if you want to use any other functionality that is not provided - # by ActionController::API out of the box. - class API < Metal - abstract! - - # Shortcut helper that returns all the ActionController::API modules except - # the ones passed as arguments: - # - # class MyAPIBaseController < ActionController::Metal - # ActionController::API.without_modules(:ForceSSL, :UrlFor).each do |left| - # include left - # end - # end - # - # This gives better control over what you want to exclude and makes it easier - # to create an API controller class, instead of listing the modules required - # manually. - def self.without_modules(*modules) - modules = modules.map do |m| - m.is_a?(Symbol) ? ActionController.const_get(m) : m - end - - MODULES - modules - end - - MODULES = [ - AbstractController::Rendering, - - UrlFor, - Redirecting, - ApiRendering, - Renderers::All, - ConditionalGet, - BasicImplicitRender, - StrongParameters, - - ForceSSL, - DataStreaming, - - # Before callbacks should also be executed as early as possible, so - # also include them at the bottom. - AbstractController::Callbacks, - - # Append rescue at the bottom to wrap as much as possible. - Rescue, - - # Add instrumentations hooks at the bottom, to ensure they instrument - # all the methods properly. - Instrumentation, - - # Params wrapper should come before instrumentation so they are - # properly showed in logs - ParamsWrapper - ] - - MODULES.each do |mod| - include mod - end - - ActiveSupport.run_load_hooks(:action_controller_api, self) - ActiveSupport.run_load_hooks(:action_controller, self) - end -end diff --git a/lib/action_controller/api/api_rendering.rb b/lib/action_controller/api/api_rendering.rb deleted file mode 100644 index 52e9f60fc..000000000 --- a/lib/action_controller/api/api_rendering.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module ActionController - module ApiRendering - extend ActiveSupport::Concern - - included do - include Rendering - end - - def render_to_body(options = {}) - _process_options(options) - super - end - end -end \ No newline at end of file diff --git a/lib/action_controller/metal/basic_implicit_render.rb b/lib/action_controller/metal/basic_implicit_render.rb deleted file mode 100644 index 9030ea585..000000000 --- a/lib/action_controller/metal/basic_implicit_render.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module ActionController - module BasicImplicitRender # :nodoc: - def send_action(method, *args) - super.tap { default_render unless performed? } - end - - def default_render(*args) - head :no_content - end - end -end \ No newline at end of file diff --git a/lib/deserializers/xml/contact.rb b/lib/deserializers/xml/contact.rb new file mode 100644 index 000000000..4dd29c683 --- /dev/null +++ b/lib/deserializers/xml/contact.rb @@ -0,0 +1,61 @@ +module Deserializers + module Xml + class Contact + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + attributes = { + name: if_present('postalInfo name'), + org_name: if_present('postalInfo org'), + email: if_present('email'), + fax: if_present('fax'), + phone: if_present('voice'), + + # Address fields + city: if_present('postalInfo addr city'), + zip: if_present('postalInfo addr pc'), + street: if_present('postalInfo addr street'), + state: if_present('postalInfo addr sp'), + country_code: if_present('postalInfo addr cc'), + + # Auth info + auth_info: if_present('authInfo pw'), + + # statuses + statuses_to_add: statuses_to_add, + statuses_to_remove: statuses_to_remove, + } + + attributes.compact + end + + def if_present(css_path) + return if frame.css(css_path).blank? + + frame.css(css_path).text + end + + def statuses_to_add + statuses_frame = frame.css('add') + return if statuses_frame.blank? + + statuses_frame.css('status').map do |status| + status['s'] + end + end + + def statuses_to_remove + statuses_frame = frame.css('rem') + return if statuses_frame.blank? + + statuses_frame.css('status').map do |status| + status['s'] + end + end + end + end +end diff --git a/lib/deserializers/xml/contact_update.rb b/lib/deserializers/xml/contact_update.rb new file mode 100644 index 000000000..b3bc6fe4a --- /dev/null +++ b/lib/deserializers/xml/contact_update.rb @@ -0,0 +1,27 @@ +require 'deserializers/xml/legal_document' +require 'deserializers/xml/ident' +require 'deserializers/xml/contact' + +module Deserializers + module Xml + class ContactUpdate + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def contact + @contact ||= ::Deserializers::Xml::Contact.new(frame).call + end + + def ident + @ident ||= ::Deserializers::Xml::Ident.new(frame).call + end + + def legal_document + @legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call + end + end + end +end diff --git a/lib/deserializers/xml/ident.rb b/lib/deserializers/xml/ident.rb new file mode 100644 index 000000000..0dc65cbb6 --- /dev/null +++ b/lib/deserializers/xml/ident.rb @@ -0,0 +1,34 @@ +module Deserializers + module Xml + class Ident + attr_reader :frame + + def initialize(frame) + @frame = frame.css('ident').first + end + + def call + if valid? + { + ident: frame.text, + ident_type: frame.attr('type'), + ident_country_code: frame.attr('cc'), + } + else + {} + end + end + + private + + def valid? + return false if frame.blank? + return false if frame.try('text').blank? + return false if frame.attr('type').blank? + return false if frame.attr('cc').blank? + + true + end + end + end +end diff --git a/lib/deserializers/xml/legal_document.rb b/lib/deserializers/xml/legal_document.rb new file mode 100644 index 000000000..b75267f2d --- /dev/null +++ b/lib/deserializers/xml/legal_document.rb @@ -0,0 +1,22 @@ +module Deserializers + module Xml + # Given a nokogiri frame, extract information about legal document from it. + class LegalDocument + attr_reader :frame + + def initialize(frame) + @frame = frame + end + + def call + ld = frame.css('legalDocument').first + return unless ld + + { + body: ld.text, + type: ld['type'], + } + end + end + end +end diff --git a/lib/gem_monkey_patches/paper_trail.rb b/lib/gem_monkey_patches/paper_trail.rb index 12a8f0c3b..2edefa91b 100644 --- a/lib/gem_monkey_patches/paper_trail.rb +++ b/lib/gem_monkey_patches/paper_trail.rb @@ -1,9 +1,9 @@ # Store console and rake changes in versions if defined?(::Rails::Console) - PaperTrail.whodunnit = "console-#{`whoami`.strip}" + PaperTrail.request.whodunnit = "console-#{`whoami`.strip}" elsif File.basename($PROGRAM_NAME) == 'rake' # rake username does not work when spring enabled - PaperTrail.whodunnit = "rake-#{`whoami`.strip} #{ARGV.join ' '}" + PaperTrail.request.whodunnit = "rake-#{`whoami`.strip} #{ARGV.join ' '}" end class PaperSession diff --git a/lib/rails5_api_controller_backport.rb b/lib/rails5_api_controller_backport.rb deleted file mode 100644 index 252332488..000000000 --- a/lib/rails5_api_controller_backport.rb +++ /dev/null @@ -1,3 +0,0 @@ -require_relative 'action_controller/metal/basic_implicit_render' -require_relative 'action_controller/api/api_rendering' -require_relative 'action_controller/api' \ No newline at end of file diff --git a/lib/serializers/registrant_api/domain.rb b/lib/serializers/registrant_api/domain.rb index 500d6c08c..542f2d0de 100644 --- a/lib/serializers/registrant_api/domain.rb +++ b/lib/serializers/registrant_api/domain.rb @@ -32,9 +32,6 @@ module Serializers period_unit: domain.period_unit, creator_str: domain.creator_str, updator_str: domain.updator_str, - legacy_id: domain.legacy_id, - legacy_registrar_id: domain.legacy_registrar_id, - legacy_registrant_id: domain.legacy_registrant_id, outzone_at: domain.outzone_at, delete_date: domain.delete_date, registrant_verification_asked_at: domain.registrant_verification_asked_at, @@ -45,11 +42,23 @@ module Serializers locked_by_registrant_at: domain.locked_by_registrant_at, status_notes: domain.status_notes, nameservers: nameservers, + dnssec_keys: dnssec_keys, + dnssec_changed_at: dnssec_updated_at, } end private + def dnssec_keys + domain.dnskeys.map do |key| + "#{key.flags} #{key.protocol} #{key.alg} #{key.public_key}" + end + end + + def dnssec_updated_at + domain.dnskeys.order(updated_at: :desc).select(:updated_at).first + end + def contacts(type) contact_pool = begin if type == :tech @@ -61,7 +70,7 @@ module Serializers array_of_contacts = [] contact_pool.map do |contact| - array_of_contacts.push(name: contact.name, id: contact.uuid) + array_of_contacts.push(name: contact.name, id: contact.uuid, email: contact.email) end array_of_contacts diff --git a/lib/tasks/data_migrations/.keep b/lib/tasks/data_migrations/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/lib/tasks/data_migrations/convert_domain_delete_date.rake b/lib/tasks/data_migrations/convert_domain_delete_date.rake deleted file mode 100644 index 7eeee5cf0..000000000 --- a/lib/tasks/data_migrations/convert_domain_delete_date.rake +++ /dev/null @@ -1,16 +0,0 @@ -namespace :data_migrations do - task convert_domain_delete_date: :environment do - processed_domain_count = 0 - - Domain.transaction do - Domain.find_each do |domain| - next unless domain.delete_date - - domain.update_columns(delete_date: domain.delete_date + 1.day) - processed_domain_count += 1 - end - end - - puts "Domains processed: #{processed_domain_count}" - end -end \ No newline at end of file diff --git a/lib/tasks/data_migrations/regenerate_registrar_reference_numbers.rake b/lib/tasks/data_migrations/regenerate_registrar_reference_numbers.rake deleted file mode 100644 index 6f6aaebe2..000000000 --- a/lib/tasks/data_migrations/regenerate_registrar_reference_numbers.rake +++ /dev/null @@ -1,16 +0,0 @@ -namespace :data_migrations do - task regenerate_registrar_reference_numbers: [:environment] do - processed_registrar_count = 0 - - Registrar.transaction do - Registrar.all.each do |registrar| - next unless registrar.reference_no.start_with?('RF') - - registrar.update_columns(reference_no: Billing::ReferenceNo.generate) - processed_registrar_count += 1 - end - end - - puts "Registrars processed: #{processed_registrar_count}" - end -end diff --git a/lib/tasks/dev/create_bank_transactions/create_bank_transactions.rake b/lib/tasks/dev/create_bank_transactions/create_bank_transactions.rake index 33614d049..17b7586e2 100644 --- a/lib/tasks/dev/create_bank_transactions/create_bank_transactions.rake +++ b/lib/tasks/dev/create_bank_transactions/create_bank_transactions.rake @@ -3,12 +3,9 @@ namespace :dev do remitter_iban = ENV['remitter_iban'] beneficiary_iban = Setting.registry_iban - keystore_password = ENV['lhv_keystore_password'] - keystore_alias = ENV['lhv_keystore_alias'] - keystore = Keystores::JavaKeystore.new - keystore.load(ENV['lhv_keystore'], keystore_password) - cert = keystore.get_certificate(keystore_alias) - key = keystore.get_key(keystore_alias, keystore_password) + keystore = OpenSSL::PKCS12.new(File.read(ENV['lhv_p12_keystore']), ENV['lhv_keystore_password']) + key = keystore.key + cert = keystore.certificate api_base_uri = URI.parse('https://testconnect.lhv.eu/connect-prelive') request_headers = { 'content-type' => 'application/xml' } @@ -38,4 +35,4 @@ namespace :dev do end end end -end \ No newline at end of file +end diff --git a/lib/tasks/invoices/process_payments.rake b/lib/tasks/invoices/process_payments.rake index 6e4c57213..340aba187 100644 --- a/lib/tasks/invoices/process_payments.rake +++ b/lib/tasks/invoices/process_payments.rake @@ -2,12 +2,9 @@ namespace :invoices do task process_payments: :environment do registry_bank_account_iban = Setting.registry_iban - keystore_password = ENV['lhv_keystore_password'] - keystore_alias = ENV['lhv_keystore_alias'] - keystore = Keystores::JavaKeystore.new - keystore.load(ENV['lhv_keystore'], keystore_password) - cert = keystore.get_certificate(keystore_alias) - key = keystore.get_key(keystore_alias, keystore_password) + keystore = OpenSSL::PKCS12.new(File.read(ENV['lhv_p12_keystore']), ENV['lhv_keystore_password']) + key = keystore.key + cert = keystore.certificate api = Lhv::ConnectApi.new api.cert = cert @@ -46,4 +43,4 @@ namespace :invoices do puts "Transactions processed: #{incoming_transactions.size}" end -end \ No newline at end of file +end diff --git a/lib/tasks/verify_email.rake b/lib/tasks/verify_email.rake new file mode 100644 index 000000000..d49bb38b9 --- /dev/null +++ b/lib/tasks/verify_email.rake @@ -0,0 +1,23 @@ +namespace :verify_email do + desc 'Stars verifying email jobs for all the domain' + task all_domains: :environment do + verifications_by_domain = EmailAddressVerification.not_verified_recently.group_by(&:domain) + verifications_by_domain.each do |_domain, verifications| + ver = verifications.sample # Verify random email to not to clog the SMTP servers + VerifyEmailsJob.enqueue(ver.id) + next + end + end + + # Need to be run like 'bundle exec rake verify_email:domain['gmail.com']' + # In zsh syntax will be 'bundle exec rake verify_email:domain\['gmail.com'\]' + # Default 'bundle exec rake verify_email:domain' wil use 'internet.ee' domain + desc 'Stars verifying email jobs for domain stated in argument' + task :domain, [:domain_name] => [:environment] do |_task, args| + args.with_defaults(domain_name: 'internet.ee') + + verifications_by_domain = EmailAddressVerification.not_verified_recently + .by_domain(args[:domain_name]) + verifications_by_domain.map { |ver| VerifyEmailsJob.enqueue(ver.id) } + end +end diff --git a/lib/tasks/whois.rake b/lib/tasks/whois.rake index c38b2c5ba..52be7e17f 100644 --- a/lib/tasks/whois.rake +++ b/lib/tasks/whois.rake @@ -35,6 +35,11 @@ namespace :whois do ReservedDomain.find_in_batches.each do |group| UpdateWhoisRecordJob.enqueue group.map(&:name), 'reserved' end + + print "\n-----> Update disputed domains whois_records" + Dispute.active.find_in_batches.each do |group| + UpdateWhoisRecordJob.enqueue group.map(&:domain_name), 'disputed' + end end puts "\n-----> all done in #{(Time.zone.now.to_f - start).round(2)} seconds" end diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb index 036ecd382..b31489691 100644 --- a/test/application_system_test_case.rb +++ b/test/application_system_test_case.rb @@ -17,7 +17,7 @@ class ApplicationSystemTestCase < ActionDispatch::IntegrationTest end class JavaScriptApplicationSystemTestCase < ApplicationSystemTestCase - self.use_transactional_fixtures = false + self.use_transactional_tests = false DatabaseCleaner.strategy = :truncation Capybara.register_driver(:chrome) do |app| diff --git a/test/fixtures/account_activities.yml b/test/fixtures/account_activities.yml index dbe1dc2aa..8f883e424 100644 --- a/test/fixtures/account_activities.yml +++ b/test/fixtures/account_activities.yml @@ -2,4 +2,4 @@ one: account: cash invoice: one bank_transaction: one - created_at: <%= Time.zone.parse('2010-07-05 10:00') %> \ No newline at end of file + created_at: <%= Time.zone.parse('2010-07-05 10:00') %> diff --git a/test/fixtures/bank_transactions.yml b/test/fixtures/bank_transactions.yml index ada80981d..70b3b6651 100644 --- a/test/fixtures/bank_transactions.yml +++ b/test/fixtures/bank_transactions.yml @@ -1,5 +1,5 @@ one: sum: 1 currency: EUR - description: Order nr. 1 - iban: US75512108001245126199 \ No newline at end of file + description: Order nr 1 from registrar 1234567 second number 2345678 + iban: US75512108001245126199 diff --git a/test/fixtures/blocked_domains.yml b/test/fixtures/blocked_domains.yml index 4bf0d0299..52c9beec2 100644 --- a/test/fixtures/blocked_domains.yml +++ b/test/fixtures/blocked_domains.yml @@ -1,2 +1,4 @@ one: name: blocked.test +idn: + name: blockedäöüõ.test diff --git a/test/fixtures/certificates.yml b/test/fixtures/certificates.yml new file mode 100644 index 000000000..4799743ff --- /dev/null +++ b/test/fixtures/certificates.yml @@ -0,0 +1,14 @@ +api: + api_user: api_bestnames + common_name: registry.test + crt: "-----BEGIN CERTIFICATE-----\nMIICYjCCAcugAwIBAgIBADANBgkqhkiG9w0BAQ0FADBNMQswCQYDVQQGEwJ1czEO\nMAwGA1UECAwFVGV4YXMxFjAUBgNVBAoMDVJlZ2lzdHJ5IHRlc3QxFjAUBgNVBAMM\nDXJlZ2lzdHJ5LnRlc3QwIBcNMjAwNTA1MTIzNzQxWhgPMjEyMDA0MTExMjM3NDFa\nME0xCzAJBgNVBAYTAnVzMQ4wDAYDVQQIDAVUZXhhczEWMBQGA1UECgwNUmVnaXN0\ncnkgdGVzdDEWMBQGA1UEAwwNcmVnaXN0cnkudGVzdDCBnzANBgkqhkiG9w0BAQEF\nAAOBjQAwgYkCgYEAyn+GCkUJIhdXVBOPrZH+Zj2B/tQfL5TLZwVYZQt38x6GQT+4\n6ndty467IJvKSUlHej7uMpsCzC8Ffmda4cZm16jO1vUb4hXIrmeKP84zLrrUpKag\ngZR4rBDbG2+uL4SzMyy3yeQysYuTiQ4N1i4vdhvkKYPSWIht/QFvuzdFq+0CAwEA\nAaNQME4wHQYDVR0OBBYEFD6B5j6NnMCDBnfbtjBYKBJM7sCRMB8GA1UdIwQYMBaA\nFD6B5j6NnMCDBnfbtjBYKBJM7sCRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN\nBQADgYEArtCR6VOabD3nM/KlZTmHMZVT4ntenYlNTM9FS0RatzPmdh4REhykvmZs\nOlBcpoV5tN5Y8bHOVRqY9V2e903QEhQgoccQhbt0Py6uFwfLv+WLKAUbeGnPqK9d\ndL3wXN9BQs0hJA6IZNFyz2F/gSTURrD1zWW2na3ipRzhupW5+98=\n-----END CERTIFICATE-----\n" + md5: e6771ed5dc857a1dbcc1e0a36baa1fee + interface: api + revoked: false +registrar: + api_user: api_bestnames + common_name: registry.test + crt: "-----BEGIN CERTIFICATE-----\nMIICYjCCAcugAwIBAgIBADANBgkqhkiG9w0BAQ0FADBNMQswCQYDVQQGEwJ1czEO\nMAwGA1UECAwFVGV4YXMxFjAUBgNVBAoMDVJlZ2lzdHJ5IHRlc3QxFjAUBgNVBAMM\nDXJlZ2lzdHJ5LnRlc3QwIBcNMjAwNTA1MTIzNzQxWhgPMjEyMDA0MTExMjM3NDFa\nME0xCzAJBgNVBAYTAnVzMQ4wDAYDVQQIDAVUZXhhczEWMBQGA1UECgwNUmVnaXN0\ncnkgdGVzdDEWMBQGA1UEAwwNcmVnaXN0cnkudGVzdDCBnzANBgkqhkiG9w0BAQEF\nAAOBjQAwgYkCgYEAyn+GCkUJIhdXVBOPrZH+Zj2B/tQfL5TLZwVYZQt38x6GQT+4\n6ndty467IJvKSUlHej7uMpsCzC8Ffmda4cZm16jO1vUb4hXIrmeKP84zLrrUpKag\ngZR4rBDbG2+uL4SzMyy3yeQysYuTiQ4N1i4vdhvkKYPSWIht/QFvuzdFq+0CAwEA\nAaNQME4wHQYDVR0OBBYEFD6B5j6NnMCDBnfbtjBYKBJM7sCRMB8GA1UdIwQYMBaA\nFD6B5j6NnMCDBnfbtjBYKBJM7sCRMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEN\nBQADgYEArtCR6VOabD3nM/KlZTmHMZVT4ntenYlNTM9FS0RatzPmdh4REhykvmZs\nOlBcpoV5tN5Y8bHOVRqY9V2e903QEhQgoccQhbt0Py6uFwfLv+WLKAUbeGnPqK9d\ndL3wXN9BQs0hJA6IZNFyz2F/gSTURrD1zWW2na3ipRzhupW5+98=\n-----END CERTIFICATE-----\n" + md5: e6771ed5dc857a1dbcc1e0a36baa1fee + interface: registrar + revoked: false diff --git a/test/fixtures/contacts.yml b/test/fixtures/contacts.yml index ddfbfe93f..0173d56dd 100644 --- a/test/fixtures/contacts.yml +++ b/test/fixtures/contacts.yml @@ -85,3 +85,11 @@ invalid: auth_info: any registrar: bestnames uuid: bd80c0f9-26ee-49e0-a2cb-2311d931c433 + +invalid_email: + name: any + code: invalid_email + email: invalid@invalid. + auth_info: any + registrar: bestnames + uuid: fa8c4f51-a221-4628-b3c6-47995f4edea3 diff --git a/test/fixtures/disputes.yml b/test/fixtures/disputes.yml new file mode 100644 index 000000000..222897ecc --- /dev/null +++ b/test/fixtures/disputes.yml @@ -0,0 +1,22 @@ +active: + domain_name: active-dispute.test + password: active-001 + starts_at: <%= Date.parse '2010-07-05' %> + expires_at: <%= Date.parse '2013-07-05' %> +future: + domain_name: future-dispute.test + password: active-001 + starts_at: <%= Date.parse '2010-10-05' %> + expires_at: <%= Date.parse '2013-10-05' %> +expired: + domain_name: shop.test + password: active-001 + starts_at: <%= Date.parse '2010-07-05' %> + expires_at: <%= Date.parse '2013-07-05' %> + closed: <%= Date.parse '2013-07-05' %> +closed: + domain_name: closed_dispute.test + password: active-001 + starts_at: <%= Date.parse '2010-07-05' %> + expires_at: <%= Date.parse '2013-07-05' %> + closed: <%= Date.parse '2013-07-05' %> diff --git a/test/fixtures/files/bank_statement_test.txt b/test/fixtures/files/bank_statement_test.txt new file mode 100644 index 000000000..2b00fdc88 --- /dev/null +++ b/test/fixtures/files/bank_statement_test.txt @@ -0,0 +1,6 @@ +VV 000689EE4567890123456789012005181404 +VV 220200518 M EE456789012345678901EUR Algsaldo C 0 +VV 12020051847406380MK EE456789012345678901EUR689EE123456789012345678 Registripidaja 413 ettemaks C 5000 +VV 12020051847406461MK EE456789012345678901EUR767EE012345678901234567 Hankija 303 Kulu D 5000 +VV 320200518 M EE456789012345678901EUR Lõppsaldo C 0 +VV 999 10000 diff --git a/test/fixtures/files/keystore.jks b/test/fixtures/files/keystore.jks deleted file mode 100644 index 7ce34f308..000000000 Binary files a/test/fixtures/files/keystore.jks and /dev/null differ diff --git a/test/fixtures/files/keystore.p12 b/test/fixtures/files/keystore.p12 new file mode 100644 index 000000000..962ddede2 Binary files /dev/null and b/test/fixtures/files/keystore.p12 differ diff --git a/test/fixtures/files/legaldoc.pdf b/test/fixtures/files/legaldoc.pdf new file mode 100644 index 000000000..1ddf7a0e8 Binary files /dev/null and b/test/fixtures/files/legaldoc.pdf differ diff --git a/test/fixtures/files/test_ca/certs/ca.crt.pem b/test/fixtures/files/test_ca/certs/ca.crt.pem new file mode 100644 index 000000000..f03e09f52 --- /dev/null +++ b/test/fixtures/files/test_ca/certs/ca.crt.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGDDCCA/SgAwIBAgIJAKaLNUIy97o1MA0GCSqGSIb3DQEBCwUAMIGVMQswCQYD +VQQGEwJFRTERMA8GA1UECAwISGFyanVtYWExEDAOBgNVBAcMB1RhbGxpbm4xIzAh +BgNVBAoMGkVlc3RpIEludGVybmV0aSBTaWh0YXN1dHVzMRowGAYDVQQDDBFlcHBf +cHJveHkgdGVzdCBjYTEgMB4GCSqGSIb3DQEJARYRaGVsbG9AaW50ZXJuZXQuZWUw +HhcNMTkwNzExMTMwMDEzWhcNMjAwNzEwMTMwMDEzWjCBlTELMAkGA1UEBhMCRUUx +ETAPBgNVBAgMCEhhcmp1bWFhMRAwDgYDVQQHDAdUYWxsaW5uMSMwIQYDVQQKDBpF +ZXN0aSBJbnRlcm5ldGkgU2lodGFzdXR1czEaMBgGA1UEAwwRZXBwX3Byb3h5IHRl +c3QgY2ExIDAeBgkqhkiG9w0BCQEWEWhlbGxvQGludGVybmV0LmVlMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0PBwqZUeXZaR3mk3VTm7S78Xs4WDCfyi +RocHDU7cWhrBvFD5ZXzmbUJPPJHmljYAOLWLEyMzw0bvYVz2FSOCkBerxGFA4T17 +RhjDEAmMMWiBAoFj6tNmxj3bq7nZfwaOY6KIxGiZcqx4usOQ3tQ+cxvrqzFVyX24 +KScmx4l2HlmJu2boF8/C4LSYvGPys+2WKXlLr73gL+cmM7Z2Y+mNgURCKT9ODpFp +VdX9iTpmnF0UFmYq/cN8QFSNv0ErsMFDZWxAnDoy6gZzsUz3ZnznOdjB96PFV9aA +Rm5BYr7jMhu7rJPOyQNd9SfD6QhlyCSjd68p6nMFvYLG5lL5QxJSTotr3VuH1uqJ +kfFwlMPJZAj/SmFUnoIvWGCyujqx6ajVX8zBvmcalSp35LyDDCnlohorUuP9TNrI +U+k/Ap6vxfxSSIOPhq6BoFxMYASp8jo+8HdFOWce5krQh/h3vvEhu015yEXH4Vgb +6lL+nvUex35He1IQFERvRSj5IB1Yw6HpwYb7LIfjXYsfas3FuSxXz9Geb23dybYd +2MlmKeGvTyjM60BNW2ZKKQ00KgnqR62bPALbDZ/AnkzxnLd7NLVqKiSBzOOkZfaO +V7hDD78VzSklA2cSV1qaBPHUW4AgQkmDJIF/1H/K9nN/F6OWKSJ0Ug3XGwDjY3Ry +X//K+E1UNWMCAwEAAaNdMFswHQYDVR0OBBYEFP135kpzvaU8ZbO5z7UVlVkIZGgQ +MB8GA1UdIwQYMBaAFP135kpzvaU8ZbO5z7UVlVkIZGgQMAwGA1UdEwQFMAMBAf8w +CwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQDF3s887Qj2eLeJln1Z/Nem +ZR2tj0PvYEHEYKq9R8N8IM1ooZt475MgyYo7XDPcuG3MMaGY9WdjqoXlWSM7T518 +U9ajFLqwNEnlfjZ33SdVDskfoRsKiDKUlvTNngn19KtAp3SBmQS6fgghlgha3tb+ +W1fOgzCRwaVG4XcQfR+wijSSovFOp+5CY/FL6XUwtFCz4ZwnHgXciG91SjhEPB+J +P8iHFr4f0qV4kKv0hPfjQ7tneeho0AzI4BXOgbRJmur6+SP/gmsgBeKr1sUHuD+d +nIAlz4T2reV8FujcW3u8yT4PFIhi0mdnXKC6xKDFlmD9AQa7eUO1DHJiSZ7zAsLS +drsqMu3GhM70Uw0Oqv2aInv8N4vwF6CJ6p/wEUXTVjkjH3U/ZzuOGcl1/5sAao0r +APwRazSMcqrjc+JicpFZ6NGTwTs0G6KD0dqhhqoyoZzB/1UDR2cG5SsgSTqBUeGb +0VMW4EYU+DG1HV+OdNrFA0RgDn5o0VF3LxwAs5ErItlojFPeBDYMJvPGsMEarNHN +03JeeEK081gzLJQzFPQV1n6kE6CiGGTx4X3ptUtvvQBD/u6KNUwN5b6p5jOQBEdZ +F4PJOVZePI/dBHr98/jlcHfCOmySc+7uzPhB86OtdF/yYabImpvQ0cypZkXwzL6l +VgOJJfHQrIhSmCRVxCEJoQ== +-----END CERTIFICATE----- diff --git a/test/fixtures/files/test_ca/certs/ca.srl b/test/fixtures/files/test_ca/certs/ca.srl new file mode 100644 index 000000000..7c1fd1b47 --- /dev/null +++ b/test/fixtures/files/test_ca/certs/ca.srl @@ -0,0 +1 @@ +8728BF086E9B1CE5 diff --git a/test/fixtures/files/test_ca/crl/crl.pem b/test/fixtures/files/test_ca/crl/crl.pem new file mode 100644 index 000000000..e0e265c99 --- /dev/null +++ b/test/fixtures/files/test_ca/crl/crl.pem @@ -0,0 +1,22 @@ +-----BEGIN X509 CRL----- +MIIDkjCCAXoCAQEwDQYJKoZIhvcNAQELBQAwgZUxCzAJBgNVBAYTAkVFMREwDwYD +VQQIDAhIYXJqdW1hYTEQMA4GA1UEBwwHVGFsbGlubjEjMCEGA1UECgwaRWVzdGkg +SW50ZXJuZXRpIFNpaHRhc3V0dXMxGjAYBgNVBAMMEWVwcF9wcm94eSB0ZXN0IGNh +MSAwHgYJKoZIhvcNAQkBFhFoZWxsb0BpbnRlcm5ldC5lZRcNMTkwNzI5MDc1NTA5 +WhcNMjkwNzI2MDc1NTA5WjB+MBMCAhACFw0xOTA1MjkwNjM5MTJaMBMCAhADFw0x +OTA1MjkwODQxMDJaMBMCAhAEFw0xOTA1MzExMTI0NTJaMBMCAhAFFw0xOTA1MzEx +MTQyMjJaMBMCAhAGFw0xOTA1MzExMjQzNDlaMBMCAhAHFw0xOTA3MjkwNzU0MzRa +oDAwLjAfBgNVHSMEGDAWgBT9d+ZKc72lPGWzuc+1FZVZCGRoEDALBgNVHRQEBAIC +EAkwDQYJKoZIhvcNAQELBQADggIBAEk9pyZjqyYUdnA0Sv7RyevRUQGKbbf3EXdv +JLDyvI9rpoyuWPkMT6vPsYght0cf/wO7oaEK/uustvFEYQiJss60jI0XuczWypk9 +paKu3LhIy6Drm3locY2k0ESrgP9IwNzS5Xr0FiaWRIozbkcawte8M4Nqe8BO5prk +/5sLjv3eFnD7E445tZhu3vmXkD50FT3PLHVBEz4yS6Fx6nTiv+9QUu8NGf+bc6+o +YKPMy6Lh/wGC7p6sZJCOCjfzLAcqWfB2EW6XU8WeQcQCZ0au7zvZjQownCS9CeJV +KVsC4QiUt97FxR2gcEN2GJesywIF11X9o8s1K/Hz3+rrtU1ymoMLeumaRW24z35A +zVsdNwRfSPmt1qHlyaJaFhKG6jw5/nws+/wGFycIjWK0DSORiGCYdKD0cCjKJbNO +2QJnJlNOaCUUj8ULyiFOtZvdadc4JVW42NI/F+AFy/bnBK0uH6CenK5XwX3kEMme +KD8b5reUcVRhQdVJdAABFJlihIg05yENI7hlH1CKfy4vmlBKl+M2mW9cmNO8O6uS +KMH8/wLuLga9gYziNT1RmVNFbnpF0hc6CFtSnlVXXTlU/TrxheH8ykrHQhKEkQj+ +3krObDFDCUMKmaGu2nxRYZwLXzUe3wVl1SAxw0eEGyON/N83sLYlcrwWTVzRG3Z7 +RqRHPn+h +-----END X509 CRL----- diff --git a/test/fixtures/files/test_ca/crlnumber b/test/fixtures/files/test_ca/crlnumber new file mode 100644 index 000000000..83b33d238 --- /dev/null +++ b/test/fixtures/files/test_ca/crlnumber @@ -0,0 +1 @@ +1000 diff --git a/test/fixtures/files/test_ca/generate_certificates.sh b/test/fixtures/files/test_ca/generate_certificates.sh new file mode 100755 index 000000000..753b39ec3 --- /dev/null +++ b/test/fixtures/files/test_ca/generate_certificates.sh @@ -0,0 +1,15 @@ +# !/bin/sh +# Use localhost as common name. +openssl genrsa -out private/client.key.pem 4096 +openssl req -sha256 -config openssl.cnf -new -days 3650 -key private/client.key.pem -out csrs/client.csr.pem +openssl ca -config openssl.cnf -keyfile private/ca.key.pem -cert certs/ca.crt.pem -extensions usr_cert -notext -md sha256 -in csrs/client.csr.pem -days 3650 -out certs/client.crt.pem + +openssl genrsa -out private/revoked.key.pem 4096 +openssl req -sha256 -config openssl.cnf -new -days 3650 -key private/revoked.key.pem -out csrs/revoked.csr.pem +openssl ca -config openssl.cnf -keyfile private/ca.key.pem -cert certs/ca.crt.pem -extensions usr_cert -notext -md sha256 -in csrs/revoked.csr.pem -days 3650 -out certs/revoked.crt.pem +openssl ca -config openssl.cnf -keyfile private/ca.key.pem -cert certs/ca.crt.pem -revoke certs/revoked.crt.pem + +openssl ca -config openssl.cnf -keyfile private/ca.key.pem -cert certs/ca.crt.pem -crldays 3650 -gencrl -out crl/crl.pem + +openssl req -config openssl.cnf -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout private/apache.key -config server.csr.cnf +openssl x509 -req -in server.csr -CA certs/ca.crt.pem -CAkey private/ca.key.pem -CAcreateserial -out certs/apache.crt -days 3650 -sha256 -extfile v3.ext diff --git a/test/fixtures/files/test_ca/index.txt b/test/fixtures/files/test_ca/index.txt new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/files/test_ca/openssl.cnf b/test/fixtures/files/test_ca/openssl.cnf new file mode 100644 index 000000000..039735751 --- /dev/null +++ b/test/fixtures/files/test_ca/openssl.cnf @@ -0,0 +1,348 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = /opt/ca # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certs with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extensions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extensions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = EE +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Harjumaa + +localityName = Locality Name (eg, city) +localityName_default = Tallinn + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Eesti Interneti Sihtasutus + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (e.g. server FQDN or YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_default = hello@internet.ee +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = /opt/ca # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) +signer_digest = sha256 # Signing digest to use. (Optional) +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/test/fixtures/files/test_ca/prepare_root_ca.sh b/test/fixtures/files/test_ca/prepare_root_ca.sh new file mode 100755 index 000000000..41725eb14 --- /dev/null +++ b/test/fixtures/files/test_ca/prepare_root_ca.sh @@ -0,0 +1,8 @@ +# Prepare required files +touch index.txt +echo 1000 > serial +echo 1000 > crlnumber + +# Generate Root CA. +openssl genrsa -aes256 -out private/ca.key.pem 4096 +openssl req -config openssl.cnf -new -x509 -days 365 -key private/ca.key.pem -sha256 -extensions v3_ca -out certs/ca.crt.pem diff --git a/test/fixtures/files/test_ca/private/ca.key.pem b/test/fixtures/files/test_ca/private/ca.key.pem new file mode 100644 index 000000000..c60b8a89e --- /dev/null +++ b/test/fixtures/files/test_ca/private/ca.key.pem @@ -0,0 +1,54 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,AEB2DBECCB8452DE1D6E3F46B4AD32A8 + +i/cuYpPW2lzi/spv5ZOvF5Fw19ZNOqIl42jdxyTKnEa51xKW7nlOUFvglzYiEMS5 +rP4TWqnlBdRl1QXUv9R9zsL6DaPXs0j1kX8OxsV8ZRF6Pzb0G0uJBF7xxKb7c/8j +GP3uURESHhVc4ku6ctkChzTrUd7V4/pPEG5hLFdpgdTNodtfzDGWORFBDv2Jp0Mc +hiJFKnLaCFItRpQnqGKfDwJPRUJIIwjH1EUx+U4WDzUI5z7LhNVZ9A/07hYvSh56 +bwZ4T4CXBXxVtBPhzb5aLigqs6CGfslsQnvoajdKEHq6B1j5Yj0aDG/IYG2jNSJM +9rRbL/0/FPmKrjsbsyxskzp2vRKYOUA2G6SU4Q8db/OBwmaz7zQC+2Og6G115f6/ +TvBNsF+SfiP7YlaRs6qGJLk9NBqqdsTvTli8qGvOV3dAUp1EXB+MGsyQGitG+7+d +7XSenjHN4Lxvb0o0BBHIDv6HScIB8a1ebtLDCV45NdYyM1lsx2rOQyKwVe++TVrH +PI+vHoR+Qx1eC2m+UOzzjtRREXbwMZfe0ErvtTUC+LrU90J48u9lRZglxOR2VdjV +/eHVlTbiWgR8fcbbbBxeVOwilwXC/vRtiYHjMkbAzul4VOPRc0gRJ4VED0mpRSf0 +/n82W9fJnqhWjEV/zoqYUCWaLG/Q/FXE9o81GeI5Av5HNF7SSy3pvxvt+dvU1Cxi +mJGj/w3T5e4yAJi7tPYfRvjyD30WFgIDw3AmJly600B6QAQ2+xi1UPL5kew46haS +Z+bdRb6lPGpDhZXPGRKnTYsoHFbpoE1tYWUMzFzBF1VeCPgPrmjoXzcWVD1tnzu7 +LV01qUfNL/SFnue7oa8xsZj4WMfhB6DsalDf30GdR4HFgswO3rPKWxP2r+tnOscv +MBwlaSvzAY4bx8rLE5Yf46rDvoby/oy3P9ZGrLygraIG4QNOJvSB8esHfXTkT7Mb +IAFPnYWc8CjwsfBTP1wl0qzgbx04FOQfmfqfS67KUcxCN2RSOidhmfrzpZhYSTli +/qpbek3rRSssAZKkuN53ozW5gfwLJpeStuSM/or6C2EKEj7KWYkTEFTRxQtFDfZB +uWdO5836XlsVZdm99OqRUlR4eLqtyGYpZjfaMcjSBbmTs8U7Xxixb6FcLyp6UbeQ +Fa3RJQL3vkINuFzIsxjRi7AUjd18+pFjYC5nOEdoJQBAM83inBrjGyxSKKcdYlVt +j4srLisCMrtDOfijyLzl+cwoUod5DUn8JhgHM1ypIPQ7pk8vYFo38I2YE4I/Djuo +EO6l8SFaWRa6AI/gkBUazwPh2OX/41e/eGeRVbTgfuzlBwJHhW5hyKTD9/DSsSmU +cC96Y9X8pwggPR8s5zLzheOCS9ysEJmgCgPgw02f/Nxydy4VWtEYlIv/C37a3JB5 +Kgtz2icD80vugSF8BkkFpQjwC8fU61pDZ0SdP5WYricakSXya46BUnZk6pS1HmZC +iw6kUrPvQk8l6e0uuB2gWPIisvpoPDuxqccayUWSbZzkV+Q3t7Mjc1uTnVQDCSGo +pdJfOr1asIBSsUzhYbvw5pDBrOTtNT6k3WAdwbhQ31q+jwhzq8ESj7UQ9klsFLlc +nthCeTC6Wv0vNbIdf5YpCR21J1RxRv8XNO1HrN1/uJKcTvrpEVFopKTN5KYnOGlq +rQdA3zetvsncmmOJe+/77pVZ/GT05yCGPlEtdjSb6RJQ3hmOZAeY/KpKh7nrYH7i +Fk+N5EJJHdCbqFLQ//Xi/8Gx5wdpzJGfFx8R0XMkQ2mXwFmqYF/IFDLnMDfp0NWW +A1SVYaQcjTOkOCdVN6CJcs8dfNo3Fm8zoo+8HMO9K1wLMiQopI+UZovIguCXELsC +A+BuzsZsnSb4bFXVq4kXbHW86WfBwoPPjRtYgDXdRyOzEd4QY0wNyBn8Ab3ogJNJ +JqNTic7N9Gg6y2GvGryiEpZL10DFUpsIIx3bdXuBOQTlDRNtj2WyQ+vpMpDwW6iQ +u0zvpvZ60Qf+akU+Z6p/yLCQUZ4JNXsp6qUaEKG3WaIwlQh5bVeWEtAOAqFDS534 +4NZoW/MMpjErHcJcoi3WAVHyq03WlnaCHTRaA5KUgVhAJ+iPh49th7uDjaqlYvC2 +m+eedZuac0wrsPG0UuAZJSqtPpNL5H53WYnuGSUE3OkLxNau+9lEqG7M3lAn7/N3 +NjHiyNvT+3JHxDMK5icSQKvvjzscX57OLneF5jxufbDXCf4fZbnMgFDH0SXOJkxV +ImGAIfaNnmBMz/mpvAGHOGUQxZDRHxvR8fO6BrZBomOmYEiWrhWbp6XRJEz+62M8 +LwE9wQnoobko3xtX+90rHWUp1jIvZRoM3dHSxIEtI2mePPklHC9RpEf9qpiwY+yR +84mI/HGiC5MnBe4BN8BMI1s2pOvLKgaEf5FJRON2nAR1qTDh0BVZx9pby2fheXBr +U80cp5khOjOeNFTJfoTJcxRv43HH4U58Ce1Gra5grB8fhdBjCqUZnX2zsuAOVAcn ++bOMUcHMI9dW6og3Plb09nhTjzLlD3i2+rCBHZOlw9m3nTBALkE8iL0f5/BFxEFy +p3fX1YWoSh/XTKdaKCQsZ9xs1oCZ73h7l1F6+o/qD2PjCkOtI5PRAGmZ83FpKY0G +eRF3vM1guPaV4qpccOqN7qii3MLVEqxWbnM0+ZBfMoHIwSvWgxaallcoyhEgLwkO +9wliM4ORX+csTmdDCJl1URR7pJBRmBMX6a7fqsZPxLQ+VjhYXZDwCohuRSYRaoai +YMVp6s6KutzSt/JUSP1oDYPxIY6pfxq/LMN4R/tBK+bdhQP8EEvcJGjKkzxslThU +utQF9Ml8oBw0LmCsxRnkPfhF2d3PmNX97QPwLBN6q1PvhQLOd1s9ILKSLBN89UCM +P7BrU/m3qcXlkGbbzKjjTMqHlvoCUQnieyAKc3ugWwGc9LIAEaFTLj45B5POXKqk +TYG3ubWWgtwVtWlCO8IMjz3+8jnQ+bHoiBwVA0y3WyQvvwqeU7SnuBHb9ktURUrs +o2LrswBQbDxvfH7T7Iz2e6pvhGMegkNo3LO86e7gaC1shMs4juCT1jy2ln2XexgN +xP8Lo0hkO2UJEVs2OMBjmawbPSEg/p/7cftwMpVUV/Dgl/7viwcLy5RGJff9y5L7 +-----END RSA PRIVATE KEY----- diff --git a/test/fixtures/files/test_ca/serial b/test/fixtures/files/test_ca/serial new file mode 100644 index 000000000..83b33d238 --- /dev/null +++ b/test/fixtures/files/test_ca/serial @@ -0,0 +1 @@ +1000 diff --git a/test/fixtures/files/test_ca/server.csr b/test/fixtures/files/test_ca/server.csr new file mode 100644 index 000000000..1020d46a1 --- /dev/null +++ b/test/fixtures/files/test_ca/server.csr @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC2DCCAcACAQAwgZIxCzAJBgNVBAYTAkVFMREwDwYDVQQIDAhIYXJqdW1hYTEQ +MA4GA1UEBwwHVGFsbGlubjEZMBcGA1UECgwQRWVzdGlJbnRlcm5ldGlTQTEQMA4G +A1UECwwHQXJlbmR1czEgMB4GCSqGSIb3DQEJARYRaGVsbG9AaW50ZXJuZXQuZWUx +DzANBgNVBAMMBioudGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKqGSyKRUfemyMMZPRr803k57DzKUyf3yPkll0IeVH5QCBu+B5fmgVvpPIyGflcc +F8J+7sGO33bXprvQswqmCuKamYNevCBAtNFZ3gu4In2jFoAXfwzYr9xWnzaU4oXT +Ga2YvMSySLjcPFy2g3mxkK63zlsNQnsLpvzCWiBZyAbbbAavoxcCrQCfUYDYOlJd +sThqaray5lNtR5iM5vYam3mliDSF9UA1QtmVnYFV4KBCA/0S1HPAPq4lVHWisxvZ +Aq7bsxjvD4V6BeQSVrbKwHGBUHr941USqZUhYcIYo4djGNeKgNtcLHjTBe/n0go4 +brxKJsaczUEh9FAAx1tKde8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAkJkKR +jqptkp2vkHUH/Nnmqh9SCPD5wETGtGLZzS/ZnWAyRPHZ8Kw3XnCvyZj41EnWifWC ++0kKSpQTvhED8RPmgfE1piQtSPuFJ9f26vyag5sGPfUkBaBl6zaxpK3fDHpCercy +N5J6b1FAoWj/rhtRCMJx8OYCmurBp4BUtyYbduk0FWhdcX8uyRiLOOxaGO7ZpkEf +CEUhEarperXPqhm9NtNbPrEP15tunf5otM6FjpIoc0wFtlOUdrZBT9dE+67F8WlT +qlXUSXucrhWt/WXEiuzaj6w/J7prDr9ua/xO9qUo5aWA6QlPsSsaQl9KF9ST0qXG +hm/lggFVtkCvKv5L +-----END CERTIFICATE REQUEST----- diff --git a/test/fixtures/files/test_ca/server.csr.cnf b/test/fixtures/files/test_ca/server.csr.cnf new file mode 100644 index 000000000..b4b38b465 --- /dev/null +++ b/test/fixtures/files/test_ca/server.csr.cnf @@ -0,0 +1,14 @@ +[req] +default_bits = 2048 +prompt = no +default_md = sha256 +distinguished_name = dn + +[dn] +C=EE +ST=Harjumaa +L=Tallinn +O=EestiInternetiSA +OU=Arendus +emailAddress=hello@internet.ee +CN = *.test diff --git a/test/fixtures/files/test_ca/v3.ext b/test/fixtures/files/test_ca/v3.ext new file mode 100644 index 000000000..82646bc5b --- /dev/null +++ b/test/fixtures/files/test_ca/v3.ext @@ -0,0 +1,8 @@ +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = test +DNS.2 = registry.test diff --git a/test/fixtures/invoice_items.yml b/test/fixtures/invoice_items.yml index 19409df81..a61ef4eb0 100644 --- a/test/fixtures/invoice_items.yml +++ b/test/fixtures/invoice_items.yml @@ -4,3 +4,10 @@ one: quantity: 1 unit: pc invoice: one + +two: + description: Acme services + price: 5 + quantity: 1 + unit: pc + invoice: unpaid diff --git a/test/fixtures/invoices.yml b/test/fixtures/invoices.yml index 3fe18b4b2..6c0dca021 100644 --- a/test/fixtures/invoices.yml +++ b/test/fixtures/invoices.yml @@ -22,4 +22,32 @@ one: vat_rate: 0.1 total: 16.50 reference_no: 13 - number: 1 \ No newline at end of file + number: 1 + description: Order nr 1 from registrar 1234567 second number 2345678 + +unpaid: + issue_date: <%= Date.parse '2010-07-05' %> + due_date: <%= Date.parse '2010-07-06' %> + currency: EUR + seller_name: Seller Ltd + seller_reg_no: 1234 + seller_iban: US75512108001245126199 + seller_bank: Main Bank + seller_swift: swift + seller_email: info@seller.test + seller_country_code: US + seller_street: Main Street 1 + seller_city: New York + seller_contact_name: John Doe + buyer: bestnames + buyer_name: Buyer Ltd + buyer_reg_no: 12345 + buyer_email: info@buyer.test + buyer_country_code: GB + buyer_street: Main Street 2 + buyer_city: London + vat_rate: 0.1 + total: 16.50 + reference_no: 13 + number: 2 + description: Order nr 2 from registrar 1234567 second number 2345678 diff --git a/test/fixtures/payment_orders.yml b/test/fixtures/payment_orders.yml new file mode 100644 index 000000000..39289b7d1 --- /dev/null +++ b/test/fixtures/payment_orders.yml @@ -0,0 +1,27 @@ +everypay_issued: + type: PaymentOrders::EveryPay + status: issued + invoice: one + response: + notes: + +banklink_issued: + type: PaymentOrders::Seb + status: issued + invoice: one + response: + notes: + +paid: + type: PaymentOrders::EveryPay + status: paid + invoice: unpaid + response: "{}" + notes: + +cancelled: + type: PaymentOrders::Seb + status: cancelled + invoice: unpaid + response: "{}" + notes: User failed to make payment. Bank responded with code 1911 diff --git a/test/fixtures/registrant_verifications.yml b/test/fixtures/registrant_verifications.yml new file mode 100644 index 000000000..bc3be67db --- /dev/null +++ b/test/fixtures/registrant_verifications.yml @@ -0,0 +1,6 @@ +one: + action: confirmed + action_type: domain_delete + created_at: <%= Time.zone.parse('2010-07-05') %> + domain: shop + verification_token: 1234 diff --git a/test/integration/admin_area/disputes_test.rb b/test/integration/admin_area/disputes_test.rb new file mode 100644 index 000000000..81019bb66 --- /dev/null +++ b/test/integration/admin_area/disputes_test.rb @@ -0,0 +1,91 @@ +require 'application_system_test_case' +require 'test_helper' + +class AdminDisputesSystemTest < ApplicationSystemTestCase + include ActionView::Helpers::NumberHelper + + setup do + @dispute = disputes(:active) + @original_default_language = Setting.default_language + sign_in users(:admin) + end + + teardown do + Setting.default_language = @original_default_language + end + + def test_creates_new_dispute + assert_nil Dispute.active.find_by(domain_name: 'hospital.test') + + visit admin_disputes_path + click_on 'New disputed domain' + + fill_in 'Domain name', with: 'hospital.test' + fill_in 'Password', with: '1234' + fill_in 'Starts at', with: (Time.zone.today - 2.years).to_s + fill_in 'Comment', with: 'Sample comment' + click_on 'Save' + + assert_text 'Dispute was successfully created.' + assert_text 'hospital.test' + end + + def test_creates_new_dispute_for_unregistered_domain + assert_nil Dispute.active.find_by(domain_name: 'nonexistant.test') + + visit admin_disputes_path + click_on 'New disputed domain' + + fill_in 'Domain name', with: 'nonexistant.test' + fill_in 'Password', with: '1234' + fill_in 'Starts at', with: Time.zone.today.to_s + fill_in 'Comment', with: 'Sample comment' + click_on 'Save' + + assert_text 'Dispute was successfully created for domain that is not registered.' + assert_text 'nonexistant.test' + end + + def test_throws_error_if_starts_at_is_in_future + assert_nil Dispute.active.find_by(domain_name: 'disputed.test') + + visit admin_disputes_path + click_on 'New disputed domain' + + fill_in 'Domain name', with: 'disputed.test' + fill_in 'Password', with: '1234' + fill_in 'Starts at', with: (Time.zone.today + 2.day).to_s + fill_in 'Comment', with: 'Sample comment' + click_on 'Save' + + assert_text "Can not be greater than today's date" + end + + def test_updates_dispute + assert_not_equal Time.zone.today, @dispute.starts_at + + visit edit_admin_dispute_path(@dispute) + fill_in 'Starts at', with: Time.zone.today.to_s + click_link_or_button 'Save' + + assert_text 'Dispute was successfully updated' + assert_text Time.zone.today + end + + def test_deletes_dispute + visit delete_admin_dispute_path(@dispute) + + assert_text 'Dispute was successfully closed.' + end + + def test_can_not_create_overlapping_dispute + visit admin_disputes_path + click_on 'New disputed domain' + + fill_in 'Domain name', with: 'active-dispute.test' + fill_in 'Starts at', with: @dispute.starts_at + 1.day + click_on 'Save' + + assert_text 'Dispute already exists for this domain at given timeframe' + end +end diff --git a/test/integration/admin_area/invoices_test.rb b/test/integration/admin_area/invoices_test.rb index 204f953d8..887f57212 100644 --- a/test/integration/admin_area/invoices_test.rb +++ b/test/integration/admin_area/invoices_test.rb @@ -13,7 +13,7 @@ class AdminAreaInvoicesIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal 'application/pdf', response.headers['Content-Type'] - assert_equal 'attachment; filename="invoice-1.pdf"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"invoice-1.pdf\"; filename*=UTF-8''invoice-1.pdf", response.headers['Content-Disposition'] assert_not_empty response.body end -end \ No newline at end of file +end diff --git a/test/integration/admin_area/registrars_test.rb b/test/integration/admin_area/registrars_test.rb index 009e7c6d6..d73496899 100644 --- a/test/integration/admin_area/registrars_test.rb +++ b/test/integration/admin_area/registrars_test.rb @@ -12,7 +12,7 @@ class AdminAreaRegistrarsIntegrationTest < ActionDispatch::IntegrationTest new_iban = 'GB94BARC10201530093459' assert_not_equal new_iban, @registrar.iban - patch admin_registrar_path(@registrar), registrar: { iban: new_iban } + patch admin_registrar_path(@registrar), params: { registrar: { iban: new_iban } } @registrar.reload assert_equal new_iban, @registrar.iban diff --git a/test/integration/admin_area/zones_test.rb b/test/integration/admin_area/zones_test.rb index cf95aedc5..bf7c07d7b 100644 --- a/test/integration/admin_area/zones_test.rb +++ b/test/integration/admin_area/zones_test.rb @@ -10,7 +10,7 @@ class AdminAreaZonesIntegrationTest < ApplicationIntegrationTest new_master_nameserver = 'new.test' assert_not_equal new_master_nameserver, @zone.master_nameserver - patch admin_zone_path(@zone), zone: { master_nameserver: new_master_nameserver } + patch admin_zone_path(@zone), params: { zone: { master_nameserver: new_master_nameserver } } @zone.reload assert_equal new_master_nameserver, @zone.master_nameserver @@ -21,7 +21,7 @@ class AdminAreaZonesIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal 'text/plain', response.headers['Content-Type'] - assert_equal 'attachment; filename="test.txt"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"test.txt\"; filename*=UTF-8''test.txt", response.headers['Content-Disposition'] assert_not_empty response.body end end diff --git a/test/integration/api/domain_contacts_test.rb b/test/integration/api/domain_contacts_test.rb index e99a45825..5336cc10a 100644 --- a/test/integration/api/domain_contacts_test.rb +++ b/test/integration/api/domain_contacts_test.rb @@ -2,9 +2,9 @@ require 'test_helper' class APIDomainContactsTest < ApplicationIntegrationTest def test_replace_all_tech_contacts_of_the_current_registrar - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_nil domains(:shop).tech_contacts.find_by(code: 'william-001') assert domains(:shop).tech_contacts.find_by(code: 'john-001') @@ -14,17 +14,17 @@ class APIDomainContactsTest < ApplicationIntegrationTest def test_skip_discarded_domains domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:airport).tech_contacts.find_by(code: 'william-001') end def test_return_affected_domains_in_alphabetical_order - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok assert_equal ({ affected_domains: %w[airport.test shop.test], @@ -36,9 +36,9 @@ class APIDomainContactsTest < ApplicationIntegrationTest domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :ok assert_equal %w[airport.test shop.test], JSON.parse(response.body, @@ -46,25 +46,25 @@ class APIDomainContactsTest < ApplicationIntegrationTest end def test_keep_other_tech_contacts_intact - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:shop).tech_contacts.find_by(code: 'acme-ltd-001') end def test_keep_admin_contacts_intact - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert domains(:airport).admin_contacts.find_by(code: 'william-001') end def test_restrict_contacts_to_the_current_registrar - patch '/repp/v1/domains/contacts', { current_contact_id: 'jack-001', - new_contact_id: 'william-002' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'jack-001', + new_contact_id: 'william-002' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ error: { type: 'invalid_request_error', @@ -74,9 +74,9 @@ class APIDomainContactsTest < ApplicationIntegrationTest end def test_non_existent_current_contact - patch '/repp/v1/domains/contacts', { current_contact_id: 'non-existent', - new_contact_id: 'john-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'non-existent', + new_contact_id: 'john-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ error: { type: 'invalid_request_error', param: 'current_contact_id', @@ -85,9 +85,9 @@ class APIDomainContactsTest < ApplicationIntegrationTest end def test_non_existent_new_contact - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'non-existent' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'non-existent' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ error: { type: 'invalid_request_error', param: 'new_contact_id', @@ -96,9 +96,9 @@ class APIDomainContactsTest < ApplicationIntegrationTest end def test_disallow_invalid_new_contact - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'invalid' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'invalid' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ error: { type: 'invalid_request_error', param: 'new_contact_id', @@ -107,9 +107,9 @@ class APIDomainContactsTest < ApplicationIntegrationTest end def test_disallow_self_replacement - patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001', - new_contact_id: 'william-001' }, - { 'HTTP_AUTHORIZATION' => http_auth_key } + patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001', + new_contact_id: 'william-001' }, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response :bad_request assert_equal ({ error: { type: 'invalid_request_error', message: 'New contact ID must be different from current contact ID' } }), diff --git a/test/integration/api/domain_transfers_test.rb b/test/integration/api/domain_transfers_test.rb index 7cd0874c1..aabaeb728 100644 --- a/test/integration/api/domain_transfers_test.rb +++ b/test/integration/api/domain_transfers_test.rb @@ -13,7 +13,8 @@ class APIDomainTransfersTest < ApplicationIntegrationTest end def test_returns_domain_transfers - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 200 assert_equal ({ data: [{ type: 'domain_transfer', @@ -26,17 +27,20 @@ class APIDomainTransfersTest < ApplicationIntegrationTest def test_creates_new_domain_transfer assert_difference -> { @domain.transfers.size } do - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } end end def test_approves_automatically_if_auto_approval_is_enabled - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert @domain.transfers.last.approved? end def test_assigns_new_registrar - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } @domain.reload assert_equal @new_registrar, @domain.registrar end @@ -44,7 +48,8 @@ class APIDomainTransfersTest < ApplicationIntegrationTest def test_regenerates_transfer_code @old_transfer_code = @domain.transfer_code - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } @domain.reload refute_equal @domain.transfer_code, @old_transfer_code end @@ -53,34 +58,41 @@ class APIDomainTransfersTest < ApplicationIntegrationTest @old_registrar = @domain.registrar assert_difference -> { @old_registrar.notifications.count } do - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } end end def test_duplicates_registrant_admin_and_tech_contacts assert_difference -> { @new_registrar.contacts.size }, 3 do - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } end end def test_reuses_identical_contact - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', params: request_params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_equal 1, @new_registrar.contacts.where(name: 'William').size end def test_fails_if_domain_does_not_exist - request_params = { format: :json, - data: { domainTransfers: [{ domainName: 'non-existent.test', transferCode: 'any' }] } } - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', + params: { data: { domainTransfers: [{ domainName: 'non-existent.test', + transferCode: 'any' }] } }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 400 assert_equal ({ errors: [{ title: 'non-existent.test does not exist' }] }), JSON.parse(response.body, symbolize_names: true) end def test_fails_if_transfer_code_is_wrong - request_params = { format: :json, - data: { domainTransfers: [{ domainName: 'shop.test', transferCode: 'wrong' }] } } - post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + post '/repp/v1/domain_transfers', + params: { data: { domainTransfers: [{ domainName: 'shop.test', + transferCode: 'wrong' }] } }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 400 refute_equal @new_registrar, @domain.registrar assert_equal ({ errors: [{ title: 'shop.test transfer code is wrong' }] }), @@ -90,8 +102,7 @@ class APIDomainTransfersTest < ApplicationIntegrationTest private def request_params - { format: :json, - data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } } + { data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } } end def http_auth_key diff --git a/test/integration/api/nameservers/put_test.rb b/test/integration/api/nameservers/put_test.rb index 4c35d3e77..853a20549 100644 --- a/test/integration/api/nameservers/put_test.rb +++ b/test/integration/api/nameservers/put_test.rb @@ -5,18 +5,23 @@ class APINameserversPutTest < ApplicationIntegrationTest old_nameserver_ids = [nameservers(:shop_ns1).id, nameservers(:airport_ns1).id, nameservers(:metro_ns1).id] - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test' } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } - assert_empty (old_nameserver_ids & registrars(:bestnames).nameservers(true).ids) + params = { data: { type: 'nameserver', + id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } + + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + + assert_empty (old_nameserver_ids & registrars(:bestnames).nameservers.reload.ids) end def test_saves_all_attributes - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test', - ipv4: ['192.0.2.55'], - ipv6: ['2001:db8::55'] } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test', + ipv4: ['192.0.2.55'], + ipv6: ['2001:db8::55'] } } } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } new_nameserver = domains(:shop).nameservers.find_by(hostname: 'ns55.bestnames.test') assert_equal ['192.0.2.55'], new_nameserver.ipv4 @@ -24,52 +29,60 @@ class APINameserversPutTest < ApplicationIntegrationTest end def test_keeps_other_nameserver_intact - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test' } } } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } other_nameserver_hash = nameservers(:shop_ns2).attributes - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_equal other_nameserver_hash, nameservers(:shop_ns2).reload.attributes end def test_keeps_other_registrar_nameservers_intact - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test' } } } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } nameserver_hash = nameservers(:metro_ns1).attributes - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_equal nameserver_hash, nameservers(:metro_ns1).reload.attributes end def test_returns_new_nameserver_record_and_affected_domain - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test', - ipv4: ['192.0.2.55'], - ipv6: ['2001:db8::55'] } } } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test', + ipv4: ['192.0.2.55'], + ipv6: ['2001:db8::55'] } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 200 assert_equal ({ data: { type: 'nameserver', id: 'ns55.bestnames.test', attributes: { hostname: 'ns55.bestnames.test', ipv4: ['192.0.2.55'], - ipv6: ['2001:db8::55'] }}, + ipv6: ['2001:db8::55'] } }, affected_domains: ["airport.test", "shop.test"] }), JSON.parse(response.body, symbolize_names: true) end def test_optional_params - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: 'ns55.bestnames.test' } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response 200 end def test_non_existent_nameserver_hostname - request_params = { format: :json, data: { type: 'nameserver', id: 'non-existent.test', - attributes: { hostname: 'any.bestnames.test' } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + params = { data: { type: 'nameserver', id: 'non-existent.test', + attributes: { hostname: 'any.bestnames.test' } } } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 404 assert_equal ({ errors: [{ title: 'Hostname non-existent.test does not exist' }] }), @@ -77,9 +90,10 @@ class APINameserversPutTest < ApplicationIntegrationTest end def test_invalid_request_params - request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', - attributes: { hostname: '' } } } - put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + params = { data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: '' } } } + put '/repp/v1/registrar/nameservers', params: params, as: :json, + headers: { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 400 assert_equal ({ errors: [{ title: 'Hostname is missing' }] }), diff --git a/test/integration/api/registrant/registrant_api_authentication_test.rb b/test/integration/api/registrant/registrant_api_authentication_test.rb index 10858d005..9daeabfca 100644 --- a/test/integration/api/registrant/registrant_api_authentication_test.rb +++ b/test/integration/api/registrant/registrant_api_authentication_test.rb @@ -20,7 +20,7 @@ class RegistrantApiAuthenticationTest < ApplicationIntegrationTest last_name: 'Smith', } - post '/api/v1/registrant/auth/eid', params + post '/api/v1/registrant/auth/eid', params: params assert(User.find_by(registrant_ident: 'EE-30110100103')) json = JSON.parse(response.body, symbolize_names: true) @@ -29,7 +29,7 @@ class RegistrantApiAuthenticationTest < ApplicationIntegrationTest def test_request_returns_existing_user assert_no_changes User.count do - post '/api/v1/registrant/auth/eid', @user_hash + post '/api/v1/registrant/auth/eid', params: @user_hash end end @@ -38,7 +38,7 @@ class RegistrantApiAuthenticationTest < ApplicationIntegrationTest @original_whitelist_ip = ENV['registrant_api_auth_allowed_ips'] ENV['registrant_api_auth_allowed_ips'] = '1.2.3.4' - post '/api/v1/registrant/auth/eid', params + post '/api/v1/registrant/auth/eid', params: params assert_equal(401, response.status) json_body = JSON.parse(response.body, symbolize_names: true) @@ -50,7 +50,7 @@ class RegistrantApiAuthenticationTest < ApplicationIntegrationTest def test_request_documented_parameters_are_required params = { foo: :bar, test: :test } - post '/api/v1/registrant/auth/eid', params + post '/api/v1/registrant/auth/eid', params: params json = JSON.parse(response.body, symbolize_names: true) assert_equal({ errors: [{ ident: ['parameter is required'] }] }, json) assert_equal(422, response.status) diff --git a/test/integration/api/registrant/registrant_api_contacts_test.rb b/test/integration/api/registrant/registrant_api_contacts_test.rb index 0658ecac1..c2950a5f8 100644 --- a/test/integration/api/registrant/registrant_api_contacts_test.rb +++ b/test/integration/api/registrant/registrant_api_contacts_test.rb @@ -14,18 +14,19 @@ class RegistrantApiContactsTest < ApplicationIntegrationTest contacts(:william).update!(ident: '1234', ident_type: 'priv', ident_country_code: 'US') assert_equal 3, @user.contacts.size - get '/api/v1/registrant/contacts', { 'limit' => 1, 'offset' => 0 }, @auth_headers + get '/api/v1/registrant/contacts', params: { 'limit' => 1, 'offset' => 0 }, + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(200, response.status) assert_equal(1, response_json.count) - get '/api/v1/registrant/contacts', {}, @auth_headers + get '/api/v1/registrant/contacts', headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(3, response_json.count) end def test_get_contact_details_by_uuid - get api_v1_registrant_contact_path(@contact.uuid), nil, @auth_headers + get api_v1_registrant_contact_path(@contact.uuid), headers: @auth_headers assert_response :ok response_json = JSON.parse(response.body, symbolize_names: true) @@ -33,21 +34,23 @@ class RegistrantApiContactsTest < ApplicationIntegrationTest end def test_root_does_not_accept_limit_higher_than_200 - get '/api/v1/registrant/contacts', { 'limit' => 400, 'offset' => 0 }, @auth_headers + get '/api/v1/registrant/contacts', params: { 'limit' => 400, 'offset' => 0 }, + headers: @auth_headers assert_equal(400, response.status) response_json = JSON.parse(response.body, symbolize_names: true) assert_equal({ errors: [{ limit: ['parameter is out of range'] }] }, response_json) end def test_root_does_not_accept_offset_lower_than_0 - get '/api/v1/registrant/contacts', { 'limit' => 200, 'offset' => "-10" }, @auth_headers + get '/api/v1/registrant/contacts', params: { 'limit' => 200, 'offset' => "-10" }, + headers: @auth_headers assert_equal(400, response.status) response_json = JSON.parse(response.body, symbolize_names: true) assert_equal({ errors: [{ offset: ['parameter is out of range'] }] }, response_json) end def test_root_returns_401_without_authorization - get '/api/v1/registrant/contacts', {}, {} + get '/api/v1/registrant/contacts' assert_equal(401, response.status) json_body = JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/api/registrant/registrant_api_cors_headers_test.rb b/test/integration/api/registrant/registrant_api_cors_headers_test.rb index 6bb768bc3..3b9fa46dc 100644 --- a/test/integration/api/registrant/registrant_api_cors_headers_test.rb +++ b/test/integration/api/registrant/registrant_api_cors_headers_test.rb @@ -2,13 +2,13 @@ require 'test_helper' class RegistrantApiCorsHeadersTest < ApplicationIntegrationTest def test_returns_200_response_code_for_options_request - options '/api/v1/registrant/auth/eid', {}, { 'Origin' => 'https://example.com' } - + process :options, api_v1_registrant_auth_eid_path, + headers: { 'Origin' => 'https://example.com' } assert_equal('200', response.code) end def test_returns_expected_headers_for_options_requests - options '/api/v1/registrant/auth/eid', {}, { 'Origin' => 'https://example.com' } + process :options, api_v1_registrant_auth_eid_path, headers: { 'Origin' => 'https://example.com' } assert_equal('https://example.com', response.headers['Access-Control-Allow-Origin']) assert_equal('POST, GET, PUT, PATCH, DELETE, OPTIONS', @@ -20,16 +20,15 @@ class RegistrantApiCorsHeadersTest < ApplicationIntegrationTest end def test_returns_empty_body - options '/api/v1/registrant/auth/eid', { 'Origin' => 'https://example.com' } - + process :options, api_v1_registrant_auth_eid_path, headers: { 'Origin' => 'https://example.com' } assert_equal('', response.body) end def test_it_returns_cors_headers_for_other_requests - post '/api/v1/registrant/auth/eid', {}, { 'Origin' => 'https://example.com' } + post '/api/v1/registrant/auth/eid', headers: { 'Origin' => 'https://example.com' } assert_equal('https://example.com', response.headers['Access-Control-Allow-Origin']) - get '/api/v1/registrant/contacts', {}, { 'Origin' => 'https://example.com' } + get '/api/v1/registrant/contacts', headers: { 'Origin' => 'https://example.com' } assert_equal('https://example.com', response.headers['Access-Control-Allow-Origin']) end end diff --git a/test/integration/api/registrant/registrant_api_domains_test.rb b/test/integration/api/registrant/registrant_api_domains_test.rb index 9095323f2..22516fecc 100644 --- a/test/integration/api/registrant/registrant_api_domains_test.rb +++ b/test/integration/api/registrant/registrant_api_domains_test.rb @@ -12,7 +12,7 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_get_domain_details_by_uuid - get '/api/v1/registrant/domains/5edda1a5-3548-41ee-8b65-6d60daf85a37', {}, @auth_headers + get '/api/v1/registrant/domains/5edda1a5-3548-41ee-8b65-6d60daf85a37', headers: @auth_headers assert_equal(200, response.status) domain = JSON.parse(response.body, symbolize_names: true) @@ -20,17 +20,25 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest assert_equal('hospital.test', domain[:name]) assert_equal('5edda1a5-3548-41ee-8b65-6d60daf85a37', domain[:id]) assert_equal({name: 'John', id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957'}, domain[:registrant]) - assert_equal([{name: 'John', id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957'}], + assert_equal([{name: 'John', + id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957', + email: 'john@inbox.test'}], domain[:admin_contacts]) - assert_equal([{name: 'John', id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957'}], + assert_equal([{name: 'John', + id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957', + email: 'john@inbox.test'}], domain[:tech_contacts]) assert_equal({ name: 'Good Names', website: nil }, domain[:registrar]) + assert_equal([], domain[:nameservers]) + assert_equal([], domain[:dnssec_keys]) + assert(domain.has_key?(:dnssec_changed_at)) + assert(domain.has_key?(:locked_by_registrant_at)) end def test_get_non_existent_domain_details_by_uuid - get '/api/v1/registrant/domains/random-uuid', {}, @auth_headers + get '/api/v1/registrant/domains/random-uuid', headers: @auth_headers assert_equal(404, response.status) response_json = JSON.parse(response.body, symbolize_names: true) @@ -38,7 +46,7 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_root_returns_domain_list - get '/api/v1/registrant/domains', {}, @auth_headers + get '/api/v1/registrant/domains', headers: @auth_headers assert_equal(200, response.status) response_json = JSON.parse(response.body, symbolize_names: true) @@ -50,20 +58,22 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_root_accepts_limit_and_offset_parameters - get '/api/v1/registrant/domains', { 'limit' => 2, 'offset' => 0 }, @auth_headers + get '/api/v1/registrant/domains', params: { 'limit' => 2, 'offset' => 0 }, + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(200, response.status) assert_equal(2, response_json.count) - get '/api/v1/registrant/domains', {}, @auth_headers + get '/api/v1/registrant/domains', headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(4, response_json.count) end def test_root_does_not_accept_limit_higher_than_200 - get '/api/v1/registrant/domains', { 'limit' => 400, 'offset' => 0 }, @auth_headers + get '/api/v1/registrant/domains', params: { 'limit' => 400, 'offset' => 0 }, + headers: @auth_headers assert_equal(400, response.status) response_json = JSON.parse(response.body, symbolize_names: true) @@ -71,7 +81,8 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_root_does_not_accept_offset_lower_than_0 - get '/api/v1/registrant/domains', { 'limit' => 200, 'offset' => "-10" }, @auth_headers + get '/api/v1/registrant/domains', params: { 'limit' => 200, 'offset' => "-10" }, + headers: @auth_headers assert_equal(400, response.status) response_json = JSON.parse(response.body, symbolize_names: true) @@ -79,7 +90,7 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_root_returns_401_without_authorization - get '/api/v1/registrant/domains', {}, {} + get '/api/v1/registrant/domains' assert_equal(401, response.status) json_body = JSON.parse(response.body, symbolize_names: true) @@ -87,7 +98,7 @@ class RegistrantApiDomainsTest < ApplicationIntegrationTest end def test_details_returns_401_without_authorization - get '/api/v1/registrant/domains/5edda1a5-3548-41ee-8b65-6d60daf85a37', {}, {} + get '/api/v1/registrant/domains/5edda1a5-3548-41ee-8b65-6d60daf85a37' assert_equal(401, response.status) json_body = JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/api/registrant/registrant_api_registry_locks_test.rb b/test/integration/api/registrant/registrant_api_registry_locks_test.rb index 049345fb5..fb6d13aca 100644 --- a/test/integration/api/registrant/registrant_api_registry_locks_test.rb +++ b/test/integration/api/registrant/registrant_api_registry_locks_test.rb @@ -12,7 +12,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest def test_can_lock_a_not_locked_domain post '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) @@ -27,7 +27,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest def test_locking_a_domain_creates_a_version_record assert_difference '@domain.versions.count', 1 do post '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers end @domain.reload @@ -39,7 +39,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest @domain.save post '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(422, response.status) @@ -51,7 +51,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest assert(@domain.locked_by_registrant?) post '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(422, response.status) @@ -62,7 +62,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest @domain.apply_registry_lock delete '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert(response_json[:statuses].include?(DomainStatus::OK)) @@ -73,7 +73,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest def test_cannot_unlock_a_not_locked_domain delete '/api/v1/registrant/domains/2df2c1a1-8f6a-490a-81be-8bdf29866880/registry_lock', - {}, @auth_headers + headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(422, response.status) @@ -81,8 +81,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest end def test_returns_404_when_domain_is_not_found - post '/api/v1/registrant/domains/random-uuid/registry_lock', - {}, @auth_headers + post '/api/v1/registrant/domains/random-uuid/registry_lock', headers: @auth_headers response_json = JSON.parse(response.body, symbolize_names: true) assert_equal(404, response.status) @@ -99,7 +98,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest assert_equal '1234', contact.ident assert_equal 'US', contact.ident_country_code - post api_v1_registrant_domain_registry_lock_path(domain.uuid), nil, @auth_headers + post api_v1_registrant_domain_registry_lock_path(domain.uuid), headers: @auth_headers assert_response :unauthorized response_json = JSON.parse(response.body, symbolize_names: true) @@ -109,7 +108,7 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest def test_registrant_can_lock_a_domain post '/api/v1/registrant/domains/1b3ee442-e8fe-4922-9492-8fcb9dccc69c/registry_lock', - {}, @auth_headers + headers: @auth_headers assert_equal(200, response.status) response_json = JSON.parse(response.body, symbolize_names: true) @@ -125,16 +124,25 @@ class RegistrantApiRegistryLocksTest < ApplicationIntegrationTest assert_equal 'https://bestnames.test', @domain.registrar.website post '/api/v1/registrant/domains/1b3ee442-e8fe-4922-9492-8fcb9dccc69c/registry_lock', - {}, @auth_headers + headers: @auth_headers assert_equal(200, response.status) response_json = JSON.parse(response.body, symbolize_names: true) assert_equal({ name: 'Best Names', website: 'https://bestnames.test' }, response_json[:registrar]) assert_equal({name: 'John', id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957'}, response_json[:registrant]) - assert_equal([{name: 'Jane', id: '9db3de62-2414-4487-bee2-d5c155567768'}], response_json[:admin_contacts]) - assert_equal([{name: 'William', id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb'}, - {name: 'Acme Ltd', id: 'f1dd365c-5be9-4b3d-a44e-3fa002465e4d'}].to_set, + assert_equal([{name: 'Jane', + id: '9db3de62-2414-4487-bee2-d5c155567768', + email: 'jane@mail.test' + }], + response_json[:admin_contacts]) + assert_equal([{name: 'William', + id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb', + email: 'william@inbox.test'}, + {name: 'Acme Ltd', + id: 'f1dd365c-5be9-4b3d-a44e-3fa002465e4d', + email: 'acme@outlook.test' + }].to_set, response_json[:tech_contacts].to_set) assert_equal( [{hostname: 'ns1.bestnames.test', ipv4: ['192.0.2.1'], ipv6: ['2001:db8::1']}, diff --git a/test/integration/api/v1/auctions/details_test.rb b/test/integration/api/v1/auctions/details_test.rb index 996151cee..374051258 100644 --- a/test/integration/api/v1/auctions/details_test.rb +++ b/test/integration/api/v1/auctions/details_test.rb @@ -15,18 +15,21 @@ class ApiV1AuctionDetailsTest < ActionDispatch::IntegrationTest assert_equal 'auction.test', @auction.domain assert_equal Auction.statuses[:no_bids], @auction.status - get api_v1_auction_path(@auction.uuid), nil, 'Content-Type' => Mime::JSON.to_s + get api_v1_auction_path(@auction.uuid), as: :json assert_response :ok assert_equal ({ 'id' => '1b3ee442-e8fe-4922-9492-8fcb9dccc69c', 'domain' => 'auction.test', 'status' => Auction.statuses[:no_bids] }), ActiveSupport::JSON - .decode(response.body) + .decode(response.body) end def test_auction_not_found - assert_raises ActiveRecord::RecordNotFound do - get api_v1_auction_path('non-existing-uuid'), nil, 'Content-Type' => Mime::JSON.to_s - end + expected_uuid = 'not-a-real-path' + get api_v1_auction_path(expected_uuid), as: :json + assert_response :not_found + json = JSON.parse(response.body, symbolize_names: true) + assert_equal expected_uuid, json[:uuid] + assert_equal 'Not Found', json[:error] end -end \ No newline at end of file +end diff --git a/test/integration/api/v1/auctions/list_test.rb b/test/integration/api/v1/auctions/list_test.rb index 3dfaff39e..ae3f4338f 100644 --- a/test/integration/api/v1/auctions/list_test.rb +++ b/test/integration/api/v1/auctions/list_test.rb @@ -10,19 +10,19 @@ class ApiV1AuctionListTest < ActionDispatch::IntegrationTest domain: 'auction.test', status: Auction.statuses[:started]) - get api_v1_auctions_path, nil, 'Content-Type' => Mime::JSON.to_s + get api_v1_auctions_path, as: :json assert_response :ok assert_equal ([{ 'id' => '1b3ee442-e8fe-4922-9492-8fcb9dccc69c', 'domain' => 'auction.test', 'status' => Auction.statuses[:started] }]), ActiveSupport::JSON - .decode(response.body) + .decode(response.body) end def test_does_not_return_finished_auctions @auction.update!(domain: 'auction.test', status: Auction.statuses[:awaiting_payment]) - get api_v1_auctions_path, nil, 'Content-Type' => Mime::JSON.to_s + get api_v1_auctions_path, as: :json assert_response :ok assert_empty ActiveSupport::JSON.decode(response.body) diff --git a/test/integration/api/v1/auctions/update_test.rb b/test/integration/api/v1/auctions/update_test.rb index 64b3a92f5..5b00a1052 100644 --- a/test/integration/api/v1/auctions/update_test.rb +++ b/test/integration/api/v1/auctions/update_test.rb @@ -20,47 +20,64 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest assert_equal '1b3ee442-e8fe-4922-9492-8fcb9dccc69c', @auction.uuid assert_equal 'auction.test', @auction.domain - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:awaiting_payment] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:awaiting_payment] }, + as: :json assert_response :ok assert_equal ({ 'id' => '1b3ee442-e8fe-4922-9492-8fcb9dccc69c', 'domain' => 'auction.test', 'status' => Auction.statuses[:awaiting_payment] }), ActiveSupport::JSON - .decode(response.body) + .decode(response.body) end def test_marks_as_awaiting_payment - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:awaiting_payment] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:awaiting_payment] }, + as: :json @auction.reload assert @auction.awaiting_payment? end + def test_sets_registration_deadline + deadline = (Time.zone.now + 10.days).end_of_day + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:awaiting_payment], + registration_deadline: deadline}, + as: :json + @auction.reload + + assert_in_delta @auction.registration_deadline, deadline, 1.second + end + def test_marks_as_no_bids - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:no_bids] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:no_bids] }, + as: :json @auction.reload assert @auction.no_bids? end def test_marks_as_payment_received - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_received] }, + as: :json @auction.reload assert @auction.payment_received? end def test_marks_as_payment_not_received - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_not_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_not_received] }, + as: :json @auction.reload assert @auction.payment_not_received? end def test_marks_as_domain_not_registered - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:domain_not_registered] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:domain_not_registered] }, + as: :json @auction.reload assert @auction.domain_not_registered? end @@ -69,8 +86,9 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest @auction.update!(registration_code: 'auction-001', status: Auction.statuses[:awaiting_payment]) - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_received] }, + as: :json response_json = ActiveSupport::JSON.decode(response.body) assert_not_nil response_json['registration_code'] @@ -79,8 +97,9 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest def test_conceals_registration_code_when_payment_is_not_received @auction.update!(status: Auction.statuses[:awaiting_payment]) - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_not_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_not_received] }, + as: :json response_json = ActiveSupport::JSON.decode(response.body) assert_nil response_json['registration_code'] @@ -91,8 +110,9 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest assert_equal 'auction.test', @auction.domain @whois_record.update!(updated_at: '2010-07-04') - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_received] }, + as: :json @whois_record.reload assert_equal Time.zone.parse('2010-07-05 10:00'), @whois_record.updated_at @@ -103,8 +123,9 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest assert_equal 'auction.test', @auction.domain @whois_record.delete - patch api_v1_auction_path(@auction.uuid), { status: Auction.statuses[:payment_received] } - .to_json, 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), + params: { status: Auction.statuses[:payment_received] }, + as: :json new_whois_record = Whois::Record.find_by(name: @auction.domain) assert_equal Time.zone.parse('2010-07-05 10:00'), new_whois_record.updated_at @@ -114,16 +135,20 @@ class ApiV1AuctionUpdateTest < ActionDispatch::IntegrationTest def test_inaccessible_when_ip_address_is_not_allowed ENV['auction_api_allowed_ips'] = '' - patch api_v1_auction_path(@auction.uuid), { status: 'any' }.to_json, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_auction_path(@auction.uuid), params: { status: 'any' }, as: :json assert_response :unauthorized end def test_auction_not_found - assert_raises ActiveRecord::RecordNotFound do - patch api_v1_auction_path('non-existing-uuid'), { status: Auction.statuses[:no_bids] }.to_json, - 'Content-Type' => Mime::JSON.to_s - end + expected_uuid = 'non-existing-uuid' + patch api_v1_auction_path(expected_uuid), + params: { status: Auction.statuses[:no_bids] }, + as: :json + + assert_response :not_found + json = JSON.parse(response.body, symbolize_names: true) + assert_equal expected_uuid, json[:uuid] + assert_equal 'Not Found', json[:error] end end diff --git a/test/integration/api/v1/registrant/contacts/details_test.rb b/test/integration/api/v1/registrant/contacts/details_test.rb index 073c8e2b8..901d5be92 100644 --- a/test/integration/api/v1/registrant/contacts/details_test.rb +++ b/test/integration/api/v1/registrant/contacts/details_test.rb @@ -14,8 +14,8 @@ class RegistrantApiV1ContactDetailsTest < ActionDispatch::IntegrationTest end def test_returns_contact_details - get api_v1_registrant_contact_path(@contact.uuid), nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contact_path(@contact.uuid), as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :ok assert_equal ({ id: @contact.uuid, @@ -43,8 +43,8 @@ class RegistrantApiV1ContactDetailsTest < ActionDispatch::IntegrationTest end def test_non_existent_contact - get api_v1_registrant_contact_path('non-existent'), nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contact_path('non-existent'), as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :not_found assert_equal({ errors: [base: ['Contact not found']] }, JSON.parse(response.body, @@ -52,7 +52,7 @@ class RegistrantApiV1ContactDetailsTest < ActionDispatch::IntegrationTest end def test_anonymous_user - get api_v1_registrant_contact_path(@contact.uuid), nil, 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contact_path(@contact.uuid) assert_response :unauthorized assert_equal({ errors: [base: ['Not authorized']] }, JSON.parse(response.body, @@ -66,8 +66,8 @@ class RegistrantApiV1ContactDetailsTest < ActionDispatch::IntegrationTest assert_equal 'US-1234', @user.registrant_ident CompanyRegister::Client.stub(:new, CompanyRegisterClientStub.new) do - get api_v1_registrant_contact_path(@contact.uuid), nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contact_path(@contact.uuid), as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } end response_json = JSON.parse(response.body, symbolize_names: true) @@ -78,8 +78,8 @@ class RegistrantApiV1ContactDetailsTest < ActionDispatch::IntegrationTest assert_equal 'US-1234', @user.registrant_ident @contact.update!(ident: '12345') - get api_v1_registrant_contact_path(@contact.uuid), nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contact_path(@contact.uuid), as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :not_found response_json = JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/api/v1/registrant/contacts/list_test.rb b/test/integration/api/v1/registrant/contacts/list_test.rb index 36b5cf6e3..864d56c0d 100644 --- a/test/integration/api/v1/registrant/contacts/list_test.rb +++ b/test/integration/api/v1/registrant/contacts/list_test.rb @@ -20,8 +20,7 @@ class RegistrantApiV1ContactListTest < ActionDispatch::IntegrationTest assert_equal 'US', @contact.ident_country_code assert_equal 'US-1234', @user.registrant_ident - get api_v1_registrant_contacts_path, nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contacts_path, as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token } response_json = JSON.parse(response.body, symbolize_names: true) assert_equal 1, response_json.size @@ -33,8 +32,7 @@ class RegistrantApiV1ContactListTest < ActionDispatch::IntegrationTest @contact = contacts(:acme_ltd) assert_equal 'acme-ltd-001', @contact.code - get api_v1_registrant_contacts_path, nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contacts_path, as: :json, headers: { 'HTTP_AUTHORIZATION' => auth_token } response_json = JSON.parse(response.body, symbolize_names: true) assert_equal 1, response_json.size @@ -48,8 +46,8 @@ class RegistrantApiV1ContactListTest < ActionDispatch::IntegrationTest assert_equal 'US-1234', @user.registrant_ident CompanyRegister::Client.stub(:new, CompanyRegisterClientStub.new) do - get api_v1_registrant_contacts_path, nil, 'HTTP_AUTHORIZATION' => auth_token, - 'Content-Type' => Mime::JSON.to_s + get api_v1_registrant_contacts_path, as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } end response_json = JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/api/v1/registrant/contacts/update_test.rb b/test/integration/api/v1/registrant/contacts/update_test.rb index 679ef36e1..e2e9abe9a 100644 --- a/test/integration/api/v1/registrant/contacts/update_test.rb +++ b/test/integration/api/v1/registrant/contacts/update_test.rb @@ -21,12 +21,11 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest email: 'john@shop.test', phone: '+111.1') - patch api_v1_registrant_contact_path(@contact.uuid), { name: 'William', - email: 'william@shop.test', - phone: '+222.2' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { name: 'William', + email: 'william@shop.test', + phone: '+222.2' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :ok @contact.reload @@ -37,10 +36,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest def test_notify_registrar assert_difference -> { @contact.registrar.notifications.count } do - patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { name: 'new name' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } end notification = @contact.registrar.notifications.last assert_equal 'Contact john-001 has been updated by registrant', notification.text @@ -50,10 +48,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest @contact.update!(fax: '+666.6') ENV['fax_enabled'] = 'true' - patch api_v1_registrant_contact_path(@contact.uuid), { fax: '+777.7' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { fax: '+777.7' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :ok @contact.reload @@ -63,10 +60,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest def test_fax_cannot_be_updated_when_disabled ENV['fax_enabled'] = 'false' - patch api_v1_registrant_contact_path(@contact.uuid), { fax: '+823.7' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { fax: '+823.7' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :bad_request @contact.reload @@ -80,14 +76,13 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest def test_update_address_when_enabled Setting.address_processing = true - patch api_v1_registrant_contact_path(@contact.uuid), { address: { city: 'new city', - street: 'new street', - zip: '92837', - country_code: 'RU', - state: 'new state' } }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { address: { city: 'new city', + street: 'new street', + zip: '92837', + country_code: 'RU', + state: 'new state' } }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :ok @contact.reload @@ -96,13 +91,12 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest end def test_address_is_optional_when_enabled - @contact.update!(street: 'any', zip: 'any', city: 'any', state: 'any', country_code: 'US') Setting.address_processing = true + @contact.update!(street: 'any', zip: 'any', city: 'any', state: 'any', country_code: 'US') - patch api_v1_registrant_contact_path(@contact.uuid), { name: 'any' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { name: 'any' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :ok end @@ -111,11 +105,10 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest @contact.update!(street: 'old street') Setting.address_processing = false - patch api_v1_registrant_contact_path(@contact.uuid), { address: { street: 'new street' } } - .to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), + params: { address: { street: 'new street' } }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } @contact.reload assert_response :bad_request @@ -130,10 +123,10 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest @contact.update!(ident_type: Contact::PRIV, disclosed_attributes: %w[]) - patch api_v1_registrant_contact_path(@contact.uuid), { disclosed_attributes: %w[name] }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), + params: { disclosed_attributes: %w[name] }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } @contact.reload assert_response :ok @@ -143,10 +136,10 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest def test_conceal_private_persons_data @contact.update!(ident_type: Contact::PRIV, disclosed_attributes: %w[name]) - patch api_v1_registrant_contact_path(@contact.uuid), { disclosed_attributes: [] }.to_json, - { 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s } + patch api_v1_registrant_contact_path(@contact.uuid), + params: { disclosed_attributes: [] }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } @contact.reload @@ -166,11 +159,10 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest assert_equal 'US-1234', @user.registrant_ident assert_no_changes -> { @contact.disclosed_attributes } do - patch api_v1_registrant_contact_path(@contact.uuid), { disclosed_attributes: %w[name] } - .to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), + params: { disclosed_attributes: %w[name] }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } @contact.reload end assert_response :bad_request @@ -182,10 +174,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest end def test_return_contact_details - patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { name: 'new name' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_equal ({ id: @contact.uuid, name: 'new name', code: @contact.code, @@ -211,10 +202,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest end def test_errors - patch api_v1_registrant_contact_path(@contact.uuid), { phone: 'invalid' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { phone: 'invalid' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :bad_request assert_equal ({ errors: { phone: ['Phone nr is invalid'] } }), JSON.parse(response.body, @@ -225,10 +215,9 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest assert_equal 'US-1234', @user.registrant_ident @contact.update!(ident: '12345') - patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name' }.to_json, - 'HTTP_AUTHORIZATION' => auth_token, - 'Accept' => Mime::JSON, - 'Content-Type' => Mime::JSON.to_s + patch api_v1_registrant_contact_path(@contact.uuid), params: { name: 'new name' }, + as: :json, + headers: { 'HTTP_AUTHORIZATION' => auth_token } @contact.reload assert_response :not_found @@ -236,7 +225,8 @@ class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest end def test_non_existent_contact - patch api_v1_registrant_contact_path('non-existent'), nil, 'HTTP_AUTHORIZATION' => auth_token + patch api_v1_registrant_contact_path('non-existent'), + headers: { 'HTTP_AUTHORIZATION' => auth_token } assert_response :not_found assert_equal ({ errors: [{ base: ['Not found'] }] }), JSON.parse(response.body, symbolize_names: true) diff --git a/test/integration/contact/audit_log_test.rb b/test/integration/contact/audit_log_test.rb index f0f6a4bf2..41699d595 100644 --- a/test/integration/contact/audit_log_test.rb +++ b/test/integration/contact/audit_log_test.rb @@ -5,7 +5,7 @@ class ContactAuditLogTest < ActionDispatch::IntegrationTest contact = contacts(:john) contact.legal_document_id = 1 - assert_difference 'contact.versions.count' do + assert_difference 'contact.versions.count', 1 do contact.save! end @@ -13,4 +13,4 @@ class ContactAuditLogTest < ActionDispatch::IntegrationTest assert_equal ({ legal_documents: [1] }).with_indifferent_access, contact_version.children.with_indifferent_access end -end \ No newline at end of file +end diff --git a/test/integration/domain/audit_log_test.rb b/test/integration/domain/audit_log_test.rb index 292994ca3..a17fded0d 100644 --- a/test/integration/domain/audit_log_test.rb +++ b/test/integration/domain/audit_log_test.rb @@ -14,7 +14,7 @@ class DomainAuditLogTest < ActionDispatch::IntegrationTest assert_equal registrant_id, domain.registrant_id domain.legal_document_id = legal_document_id - assert_difference 'domain.versions.count' do + assert_difference 'domain.versions.count', 1 do domain.save! end @@ -26,4 +26,4 @@ class DomainAuditLogTest < ActionDispatch::IntegrationTest assert_equal [legal_document_id], domain_version.children['legal_documents'] assert_equal [registrant_id], domain_version.children['registrant'] end -end \ No newline at end of file +end diff --git a/test/integration/epp/base_test.rb b/test/integration/epp/base_test.rb index 6d8531870..456e7b41e 100644 --- a/test/integration/epp/base_test.rb +++ b/test/integration/epp/base_test.rb @@ -15,8 +15,8 @@ class EppBaseTest < EppTestCase begin assert_difference 'ApiLog::EppLog.count' do - post '/epp/command/internal_error', { frame: valid_request_xml }, - 'HTTP_COOKIE' => 'session=api_bestnames' + post '/epp/command/internal_error', params: { frame: valid_request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :command_failed rescue @@ -32,7 +32,8 @@ class EppBaseTest < EppTestCase XML - post valid_command_path, { frame: invalid_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post valid_command_path, params: { frame: invalid_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :syntax_error end @@ -50,8 +51,8 @@ class EppBaseTest < EppTestCase XML - post epp_info_path, { frame: xml_of_epp_command_that_requires_authentication }, - 'HTTP_COOKIE' => 'session=non-existent' + post epp_info_path, params: { frame: xml_of_epp_command_that_requires_authentication }, + headers: { 'HTTP_COOKIE' => 'session=non-existent' } assert_epp_response :authorization_error end @@ -74,8 +75,8 @@ class EppBaseTest < EppTestCase XML - post epp_info_path, { frame: xml_of_epp_command_that_requires_authorization }, - 'HTTP_COOKIE' => "session=#{session.session_id}" + post epp_info_path, params: { frame: xml_of_epp_command_that_requires_authorization }, + headers: { 'HTTP_COOKIE' => "session=#{session.session_id}" } assert_epp_response :authorization_error end diff --git a/test/integration/epp/contact/base_test.rb b/test/integration/epp/contact/base_test.rb index ef10fdb35..79bb8579c 100644 --- a/test/integration/epp/contact/base_test.rb +++ b/test/integration/epp/contact/base_test.rb @@ -14,7 +14,8 @@ class EppContactBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_does_not_exist end diff --git a/test/integration/epp/contact/check/base_test.rb b/test/integration/epp/contact/check/base_test.rb index 4e630c94c..528d69d86 100644 --- a/test/integration/epp/contact/check/base_test.rb +++ b/test/integration/epp/contact/check/base_test.rb @@ -21,7 +21,8 @@ class EppContactCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -42,7 +43,8 @@ class EppContactCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '1', response_xml.at_xpath('//contact:id', contact: xml_schema)['avail'] @@ -65,7 +67,8 @@ class EppContactCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//contact:id', contact: xml_schema)['avail'] @@ -88,7 +91,8 @@ class EppContactCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal 3, response_xml.xpath('//contact:cd', contact: xml_schema).size diff --git a/test/integration/epp/contact/create/base_test.rb b/test/integration/epp/contact/create/base_test.rb index 1f749123c..262487a1e 100644 --- a/test/integration/epp/contact/create/base_test.rb +++ b/test/integration/epp/contact/create/base_test.rb @@ -29,7 +29,8 @@ class EppContactCreateBaseTest < EppTestCase XML assert_difference 'Contact.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully @@ -40,6 +41,41 @@ class EppContactCreateBaseTest < EppTestCase assert_not_empty contact.code end + def test_responces_error_with_email_error + name = 'new' + email = 'new@registrar@test' + phone = '+1.2' + + request_xml = <<-XML + + + + + + + #{name} + + #{phone} + #{email} + + + + + any + + + + + XML + + assert_no_difference 'Contact.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_epp_response :parameter_value_syntax_error + end + def test_respects_custom_code name = 'new' code = 'custom-id' @@ -68,7 +104,8 @@ class EppContactCreateBaseTest < EppTestCase XML - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => "session=#{session.session_id}" + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => "session=#{session.session_id}" } contact = Contact.find_by(name: name) assert_equal "#{session.user.registrar.code}:#{code}".upcase, contact.code @@ -98,8 +135,120 @@ class EppContactCreateBaseTest < EppTestCase XML assert_no_difference 'Contact.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :required_parameter_missing end + + def test_does_not_save_address_when_address_processing_turned_off + name = 'new' + email = 'new@registrar.test' + phone = '+1.2' + + request_xml = <<-XML + + + + + + + #{name} + + 123 Example + Tallinn + FFF + 123456 + EE + + + #{phone} + #{email} + + + + + 123 + + + + + XML + + assert_difference 'Contact.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_epp_response :completed_without_address + contact = Contact.find_by(name: name) + assert_equal name, contact.name + assert_equal email, contact.email + assert_equal phone, contact.phone + assert_not_empty contact.code + assert_nil contact.city + assert_nil contact.street + assert_nil contact.zip + assert_nil contact.country_code + assert_nil contact.state + end + + def test_saves_address_when_address_processing_turned_on + Setting.address_processing = true + + name = 'new' + email = 'new@registrar.test' + phone = '+1.2' + street = '123 Example' + city = 'Tallinn' + state = 'Harjumaa' + zip = '123456' + country_code = 'EE' + + request_xml = <<-XML + + + + + + + #{name} + + #{street} + #{city} + #{state} + #{zip} + #{country_code} + + + #{phone} + #{email} + + + + + 123 + + + + + XML + + assert_difference 'Contact.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_epp_response :completed_successfully + contact = Contact.find_by(name: name) + assert_equal name, contact.name + assert_equal email, contact.email + assert_equal phone, contact.phone + assert_not_empty contact.code + assert_equal city, contact.city + assert_equal street, contact.street + assert_equal zip, contact.zip + assert_equal country_code, contact.country_code + assert_equal state, contact.state + end end diff --git a/test/integration/epp/contact/delete/base_test.rb b/test/integration/epp/contact/delete/base_test.rb index d8ce06c95..26ba63897 100644 --- a/test/integration/epp/contact/delete/base_test.rb +++ b/test/integration/epp/contact/delete/base_test.rb @@ -21,7 +21,8 @@ class EppContactDeleteBaseTest < EppTestCase XML assert_difference 'Contact.count', -1 do - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully end @@ -47,7 +48,8 @@ class EppContactDeleteBaseTest < EppTestCase XML assert_no_difference 'Contact.count' do - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :object_association_prohibits_operation end @@ -55,7 +57,7 @@ class EppContactDeleteBaseTest < EppTestCase private def deletable_contact - Domain.update_all(registrant_id: contacts(:william)) + Domain.update_all(registrant_id: contacts(:william).id) DomainContact.delete_all contacts(:john) end diff --git a/test/integration/epp/contact/info/base_test.rb b/test/integration/epp/contact/info/base_test.rb index 6bfcc896d..80dad97e8 100644 --- a/test/integration/epp/contact/info/base_test.rb +++ b/test/integration/epp/contact/info/base_test.rb @@ -29,7 +29,8 @@ class EppContactInfoBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -43,9 +44,37 @@ class EppContactInfoBaseTest < EppTestCase contact: xml_schema).text end + def test_hides_password_when_current_registrar_is_not_sponsoring + non_sponsoring_registrar = registrars(:goodnames) + @contact.update!(registrar: non_sponsoring_registrar) + + # https://github.com/internetee/registry/issues/415 + @contact.update_columns(code: @contact.code.upcase) + + request_xml = <<-XML + + + + + + #{@contact.code} + + + + + XML + + post epp_info_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => + 'session=api_bestnames' } + + assert_epp_response :completed_successfully + response_xml = Nokogiri::XML(response.body) + assert_nil response_xml.at_xpath('//contact:authInfo', contact: xml_schema) + end + private def xml_schema 'https://epp.tld.ee/schema/contact-ee-1.1.xsd' end -end \ No newline at end of file +end diff --git a/test/integration/epp/contact/transfer/base_test.rb b/test/integration/epp/contact/transfer/base_test.rb index e76fce5e4..2d4ebb62c 100644 --- a/test/integration/epp/contact/transfer/base_test.rb +++ b/test/integration/epp/contact/transfer/base_test.rb @@ -16,7 +16,8 @@ class EppContactTransferBaseTest < EppTestCase XML - post epp_transfer_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :unimplemented end diff --git a/test/integration/epp/contact/update/base_test.rb b/test/integration/epp/contact/update/base_test.rb index ad5e58862..98c0e4462 100644 --- a/test/integration/epp/contact/update/base_test.rb +++ b/test/integration/epp/contact/update/base_test.rb @@ -37,7 +37,8 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @contact.reload assert_epp_response :completed_successfully @@ -69,7 +70,8 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_emails 1 end @@ -97,7 +99,8 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_no_emails end @@ -128,7 +131,8 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_no_emails end @@ -154,7 +158,8 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_does_not_exist end @@ -188,7 +193,8 @@ class EppContactUpdateBaseTest < EppTestCase XML assert_no_changes -> { @contact.updated_at } do - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :data_management_policy_violation end @@ -220,16 +226,110 @@ class EppContactUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :completed_successfully end + def test_updates_address_when_address_processing_turned_on + @contact.update_columns(code: @contact.code.upcase) + Setting.address_processing = true + + street = '123 Example' + city = 'Tallinn' + state = 'Harjumaa' + zip = '123456' + country_code = 'EE' + + request_xml = <<-XML + + + + + + #{@contact.code} + + + + #{street} + #{city} + #{state} + #{zip} + #{country_code} + + + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + + assert_epp_response :completed_successfully + @contact.reload + + assert_equal city, @contact.city + assert_equal street, @contact.street + assert_equal zip, @contact.zip + assert_equal country_code, @contact.country_code + assert_equal state, @contact.state + end + + def test_does_not_update_address_when_address_processing_turned_off + @contact.update_columns(code: @contact.code.upcase) + + street = '123 Example' + city = 'Tallinn' + state = 'Harjumaa' + zip = '123456' + country_code = 'EE' + + request_xml = <<-XML + + + + + + #{@contact.code} + + + + #{street} + #{city} + #{state} + #{zip} + #{country_code} + + + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + + assert_epp_response :completed_without_address + @contact.reload + + assert_nil @contact.city + assert_nil @contact.street + assert_nil @contact.zip + assert_nil @contact.country_code + assert_nil @contact.state + end + private def make_contact_free_of_domains_where_it_acts_as_a_registrant(contact) other_contact = contacts(:william) assert_not_equal other_contact, contact - Domain.update_all(registrant_id: other_contact) + Domain.update_all(registrant_id: other_contact.id) end end diff --git a/test/integration/epp/domain/base_test.rb b/test/integration/epp/domain/base_test.rb index 125e173a7..34d9fb2bd 100644 --- a/test/integration/epp/domain/base_test.rb +++ b/test/integration/epp/domain/base_test.rb @@ -14,7 +14,8 @@ class EppDomainBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_does_not_exist end diff --git a/test/integration/epp/domain/check/auction_test.rb b/test/integration/epp/domain/check/auction_test.rb index 7b4dcb595..9fee851b6 100644 --- a/test/integration/epp/domain/check/auction_test.rb +++ b/test/integration/epp/domain/check/auction_test.rb @@ -28,7 +28,8 @@ class EppDomainCheckAuctionTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -52,7 +53,8 @@ class EppDomainCheckAuctionTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -76,7 +78,8 @@ class EppDomainCheckAuctionTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -100,7 +103,8 @@ class EppDomainCheckAuctionTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -124,7 +128,8 @@ class EppDomainCheckAuctionTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully diff --git a/test/integration/epp/domain/check/base_test.rb b/test/integration/epp/domain/check/base_test.rb index bed7a5b2f..5966f6239 100644 --- a/test/integration/epp/domain/check/base_test.rb +++ b/test/integration/epp/domain/check/base_test.rb @@ -15,7 +15,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -36,7 +37,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '1', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -59,7 +61,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '1', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -80,7 +83,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -103,7 +107,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -126,7 +131,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -149,7 +155,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] @@ -172,7 +179,8 @@ class EppDomainCheckBaseTest < EppTestCase XML - post epp_check_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_check_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal 3, response_xml.xpath('//domain:cd', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').size diff --git a/test/integration/epp/domain/create/auction_idn_test.rb b/test/integration/epp/domain/create/auction_idn_test.rb index c5e9f840c..822253ee5 100644 --- a/test/integration/epp/domain/create/auction_idn_test.rb +++ b/test/integration/epp/domain/create/auction_idn_test.rb @@ -39,7 +39,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end refute Domain.where(name: @idn_auction.domain).exists? @@ -73,7 +74,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames'} end refute Domain.where(name: @idn_auction.domain).exists? @@ -106,7 +108,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames'} end refute Domain.where(name: @idn_auction.domain).exists? @@ -139,7 +142,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames'} end refute Domain.where(name: @idn_auction.domain).exists? @@ -176,7 +180,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames'} end @idn_auction.reload @@ -212,7 +217,8 @@ class EppDomainCreateAuctionIdnTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames'} end @idn_auction.reload diff --git a/test/integration/epp/domain/create/auction_test.rb b/test/integration/epp/domain/create/auction_test.rb index 863f473a7..7e4c2ecb7 100644 --- a/test/integration/epp/domain/create/auction_test.rb +++ b/test/integration/epp/domain/create/auction_test.rb @@ -31,7 +31,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully end @@ -68,7 +69,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully end @@ -100,7 +102,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end @auction.reload @@ -132,7 +135,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :required_parameter_missing end @@ -164,7 +168,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :invalid_authorization_information end @@ -195,7 +200,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :required_parameter_missing end @@ -222,7 +228,8 @@ class EppDomainCreateAuctionTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :parameter_value_policy_error end diff --git a/test/integration/epp/domain/create/base_test.rb b/test/integration/epp/domain/create/base_test.rb index 8e4d28d7a..b75ef8909 100644 --- a/test/integration/epp/domain/create/base_test.rb +++ b/test/integration/epp/domain/create/base_test.rb @@ -1,6 +1,39 @@ require 'test_helper' class EppDomainCreateBaseTest < EppTestCase + + def test_not_registers_domain_without_legaldoc + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = true + now = Time.zone.parse('2010-07-05') + travel_to now + name = "new.#{dns_zones(:one).origin}" + contact = contacts(:john) + registrant = contact.becomes(Registrant) + + request_xml = <<-XML + + + + + + #{name} + #{registrant.code} + + + + + XML + + assert_no_difference 'Domain.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_epp_response :required_parameter_missing + Setting.legal_document_is_mandatory = old_value + end + def test_registers_new_domain_with_required_attributes now = Time.zone.parse('2010-07-05') travel_to now @@ -28,7 +61,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully @@ -44,6 +78,87 @@ class EppDomainCreateBaseTest < EppTestCase assert_equal now + default_registration_period, domain.expire_time end + def test_registers_domain_without_legaldoc_if_optout + now = Time.zone.parse('2010-07-05') + travel_to now + name = "new.#{dns_zones(:one).origin}" + contact = contacts(:john) + registrant = contact.becomes(Registrant) + registrar = registrant.registrar + + registrar.legaldoc_optout = true + registrar.save(validate: false) + + request_xml = <<-XML + + + + + + #{name} + #{registrant.code} + + + + + XML + + assert_difference 'Domain.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_epp_response :completed_successfully + + domain = Domain.find_by(name: name) + assert_equal name, domain.name + assert_equal registrant, domain.registrant + end + + def test_does_not_registers_domain_without_legaldoc_if_mandatory + now = Time.zone.parse('2010-07-05') + travel_to now + name = "new.#{dns_zones(:one).origin}" + contact = contacts(:john) + registrant = contact.becomes(Registrant) + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = true + registrar = registrant.registrar + + assert registrar.legaldoc_mandatory? + + request_xml = <<-XML + + + + + + #{name} + #{registrant.code} + + + + + XML + + + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + + assert_epp_response :required_parameter_missing + Setting.legal_document_is_mandatory = false + + assert_not registrar.legaldoc_mandatory? + assert_not Setting.legal_document_is_mandatory + + assert_difference 'Domain.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + Setting.legal_document_is_mandatory = old_value + end + def test_registers_reserved_domain_with_registration_code reserved_domain = reserved_domains(:one) registration_code = reserved_domain.registration_code @@ -71,7 +186,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :completed_successfully @@ -105,7 +221,8 @@ class EppDomainCreateBaseTest < EppTestCase XML - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :completed_successfully assert_equal transfer_code, Domain.find_by(name: name).transfer_code @@ -135,7 +252,38 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + assert_epp_response :data_management_policy_violation + end + + def test_blocked_punicode_domain_cannot_be_registered + blocked_domain = 'blockedäöüõ.test' + assert BlockedDomain.find_by(name: blocked_domain) + + request_xml = <<-XML + + + + + + #{SimpleIDN.to_ascii('blockedäöüõ.test')} + #{contacts(:john).code} + + + + + #{'test' * 2000} + + + + + XML + + assert_no_difference 'Domain.count' do + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :data_management_policy_violation end @@ -164,7 +312,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :invalid_authorization_information end @@ -192,7 +341,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :required_parameter_missing end @@ -220,7 +370,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => "session=#{session.session_id}" + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => "session=#{session.session_id}" } end assert_epp_response :billing_failure end @@ -248,7 +399,8 @@ class EppDomainCreateBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_create_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_create_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :billing_failure end diff --git a/test/integration/epp/domain/delete/base_test.rb b/test/integration/epp/domain/delete/base_test.rb index 0a70afe2e..c7147957c 100644 --- a/test/integration/epp/domain/delete/base_test.rb +++ b/test/integration/epp/domain/delete/base_test.rb @@ -34,7 +34,7 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_includes Domain.find_by(name: 'invalid.test').statuses, DomainStatus::PENDING_DELETE_CONFIRMATION assert_epp_response :completed_successfully_action_pending end @@ -62,7 +62,7 @@ class EppDomainDeleteBaseTest < EppTestCase XML assert_no_difference 'Domain.count' do - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :object_status_prohibits_operation end @@ -89,7 +89,7 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert @domain.registrant_verification_asked? @@ -120,7 +120,7 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_not @domain.registrant_verification_asked? @@ -151,7 +151,7 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_not @domain.registrant_verification_asked? @@ -160,8 +160,9 @@ class EppDomainDeleteBaseTest < EppTestCase assert_epp_response :completed_successfully end - def test_legal_document_is_required + def test_legal_document_is_optional assert_equal 'shop.test', @domain.name + Setting.request_confirmation_on_domain_deletion_enabled = false request_xml = <<-XML @@ -176,9 +177,9 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } - assert_epp_response :required_parameter_missing + assert_epp_response :completed_successfully end def test_domain_cannot_be_deleted_when_explicitly_prohibited_by_registrar @@ -203,8 +204,8 @@ class EppDomainDeleteBaseTest < EppTestCase XML - post epp_delete_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_status_prohibits_operation end -end \ No newline at end of file +end diff --git a/test/integration/epp/domain/info/base_test.rb b/test/integration/epp/domain/info/base_test.rb index 041c39cf3..26f0ecce1 100644 --- a/test/integration/epp/domain/info/base_test.rb +++ b/test/integration/epp/domain/info/base_test.rb @@ -21,7 +21,8 @@ class EppDomainInfoBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_epp_response :completed_successfully @@ -49,7 +50,8 @@ class EppDomainInfoBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } response_xml = Nokogiri::XML(response.body) assert_equal '65078d5', response_xml.at_xpath('//domain:authInfo/domain:pw', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text @@ -76,7 +78,8 @@ class EppDomainInfoBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_goodnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } response_xml = Nokogiri::XML(response.body) assert_equal '65078d5', response_xml.at_xpath('//domain:authInfo/domain:pw', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text @@ -99,7 +102,8 @@ class EppDomainInfoBaseTest < EppTestCase XML - post epp_info_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_goodnames' + post epp_info_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } response_xml = Nokogiri::XML(response.body) assert_nil response_xml.at_xpath('//domain:authInfo/domain:pw', diff --git a/test/integration/epp/domain/renew/base_test.rb b/test/integration/epp/domain/renew/base_test.rb index 6c11f826e..541aab2a8 100644 --- a/test/integration/epp/domain/renew/base_test.rb +++ b/test/integration/epp/domain/renew/base_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class EppDomainRenewBaseTest < EppTestCase - self.use_transactional_fixtures = false + self.use_transactional_tests = false def test_renews_domain travel_to Time.zone.parse('2010-07-05') @@ -24,7 +24,8 @@ class EppDomainRenewBaseTest < EppTestCase XML - post epp_renew_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } domain.reload assert_epp_response :completed_successfully @@ -50,7 +51,8 @@ class EppDomainRenewBaseTest < EppTestCase XML assert_no_changes -> { domain.valid_to } do - post epp_renew_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } domain.reload end assert_epp_response :object_status_prohibits_operation @@ -77,8 +79,8 @@ class EppDomainRenewBaseTest < EppTestCase XML assert_no_changes -> { domain.valid_to } do - post epp_renew_path, { frame: request_xml }, - 'HTTP_COOKIE' => "session=#{session.session_id}" + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => "session=#{session.session_id}" } domain.reload end assert_epp_response :authorization_error @@ -105,8 +107,8 @@ class EppDomainRenewBaseTest < EppTestCase XML assert_no_difference -> { domain.valid_to } do - post epp_renew_path, { frame: request_xml }, 'HTTP_COOKIE' => - "session=#{session.session_id}" + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => "session=#{session.session_id}" } domain.reload end assert_epp_response :billing_failure @@ -132,7 +134,8 @@ class EppDomainRenewBaseTest < EppTestCase XML assert_no_changes -> { domain.valid_to } do - post epp_renew_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } domain.reload end assert_epp_response :billing_failure @@ -158,7 +161,8 @@ class EppDomainRenewBaseTest < EppTestCase XML assert_no_changes -> { domain.valid_to } do - post epp_renew_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_renew_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } domain.reload end assert_epp_response :parameter_value_policy_error diff --git a/test/integration/epp/domain/transfer/query_test.rb b/test/integration/epp/domain/transfer/query_test.rb index 11e59d5ba..d6f62e223 100644 --- a/test/integration/epp/domain/transfer/query_test.rb +++ b/test/integration/epp/domain/transfer/query_test.rb @@ -2,7 +2,8 @@ require 'test_helper' class EppDomainTransferQueryTest < EppTestCase def test_returns_domain_transfer_details - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } xml_doc = Nokogiri::XML(response.body) assert_epp_response :completed_successfully assert_equal 'shop.test', xml_doc.xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text @@ -28,14 +29,16 @@ class EppDomainTransferQueryTest < EppTestCase XML - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :invalid_authorization_information end def test_no_domain_transfer domains(:shop).transfers.delete_all - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_does_not_exist end diff --git a/test/integration/epp/domain/transfer/request_test.rb b/test/integration/epp/domain/transfer/request_test.rb index caa068999..c7a838ca6 100644 --- a/test/integration/epp/domain/transfer/request_test.rb +++ b/test/integration/epp/domain/transfer/request_test.rb @@ -13,24 +13,28 @@ class EppDomainTransferRequestTest < EppTestCase end def test_transfers_domain_at_once - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } assert_epp_response :completed_successfully end def test_creates_new_domain_transfer assert_difference -> { @domain.transfers.size } do - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } end end def test_approves_automatically_if_auto_approval_is_enabled - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } assert_equal 'serverApproved', Nokogiri::XML(response.body).xpath('//domain:trStatus', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text end def test_assigns_new_registrar - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } @domain.reload assert_equal @new_registrar, @domain.registrar end @@ -38,7 +42,8 @@ class EppDomainTransferRequestTest < EppTestCase def test_regenerates_transfer_code @old_transfer_code = @domain.transfer_code - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } @domain.reload refute_equal @domain.transfer_code, @old_transfer_code @@ -48,31 +53,36 @@ class EppDomainTransferRequestTest < EppTestCase @old_registrar = @domain.registrar assert_difference -> { @old_registrar.notifications.count } do - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } end end def test_duplicates_registrant_admin_and_tech_contacts assert_difference -> { @new_registrar.contacts.size }, 3 do - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } end end def test_reuses_identical_contact - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } assert_equal 1, @new_registrar.contacts.where(name: 'William').size end def test_saves_legal_document - assert_difference -> { @domain.legal_documents(true).size } do - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + assert_difference -> { @domain.legal_documents.reload.size } do + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } end end def test_non_transferable_domain @domain.update!(statuses: [DomainStatus::SERVER_TRANSFER_PROHIBITED]) - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } domains(:shop).reload assert_equal registrars(:bestnames), domains(:shop).registrar @@ -82,7 +92,8 @@ class EppDomainTransferRequestTest < EppTestCase def test_discarded_domain_cannot_be_transferred @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } @domain.reload assert_equal registrars(:bestnames), @domain.registrar @@ -91,7 +102,8 @@ class EppDomainTransferRequestTest < EppTestCase def test_same_registrar assert_no_difference -> { @domain.transfers.size } do - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } end assert_epp_response :use_error end @@ -113,7 +125,8 @@ class EppDomainTransferRequestTest < EppTestCase XML - post epp_transfer_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + post epp_transfer_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_goodnames' } @domain.reload assert_epp_response :invalid_authorization_information diff --git a/test/integration/epp/domain/update/base_test.rb b/test/integration/epp/domain/update/base_test.rb index 29fc1b875..de1ba84d8 100644 --- a/test/integration/epp/domain/update/base_test.rb +++ b/test/integration/epp/domain/update/base_test.rb @@ -34,7 +34,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_equal 'f0ff7d17b0', @domain.transfer_code assert_epp_response :completed_successfully @@ -56,7 +57,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_status_prohibits_operation end @@ -76,7 +78,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_status_prohibits_operation response_xml = Nokogiri::XML(response.body) @@ -109,7 +112,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully_action_pending @@ -145,7 +149,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully_action_pending @@ -155,6 +160,71 @@ class EppDomainUpdateBaseTest < EppTestCase assert_verification_and_notification_emails end + def test_updates_registrant_when_legaldoc_is_not_mandatory + Setting.request_confrimation_on_registrant_change_enabled = true + new_registrant = contacts(:william) + assert_not_equal new_registrant, @domain.registrant + + @domain.registrar.legaldoc_optout = true + @domain.registrar.save(validate: false) + @domain.registrar.reload + + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + + assert_epp_response :completed_successfully_action_pending + assert_not_equal new_registrant, @domain.registrant + assert @domain.registrant_verification_asked? + assert_includes @domain.statuses, DomainStatus::PENDING_UPDATE + assert_verification_and_notification_emails + end + + def test_dows_not_update_registrant_when_legaldoc_is_mandatory + Setting.request_confrimation_on_registrant_change_enabled = true + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = true + new_registrant = contacts(:william) + assert_not_equal new_registrant, @domain.registrant + + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + assert_epp_response :required_parameter_missing + Setting.legal_document_is_mandatory = old_value + end + def test_skips_verification_when_provided_registrant_is_the_same_as_current_one Setting.request_confrimation_on_registrant_change_enabled = true @@ -179,7 +249,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully @@ -188,6 +259,49 @@ class EppDomainUpdateBaseTest < EppTestCase assert_no_emails end + def test_skips_verification_when_registrant_changed_with_dispute_password + Setting.request_confrimation_on_registrant_change_enabled = true + dispute = disputes(:expired) + dispute.update!(starts_at: Time.zone.now, expires_at: Time.zone.now + 5.days, closed: nil) + new_registrant = contacts(:william) + + assert @domain.disputed? + + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + #{'test' * 2000} + + #{dispute.password} + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + + assert_epp_response :completed_successfully + assert new_registrant, @domain.registrant + assert_not @domain.registrant_verification_asked? + assert_not @domain.disputed? + assert_no_emails + end + def test_skips_verification_when_disabled Setting.request_confrimation_on_registrant_change_enabled = false new_registrant = contacts(:william).becomes(Registrant) @@ -214,7 +328,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully @@ -250,7 +365,8 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully @@ -260,6 +376,46 @@ class EppDomainUpdateBaseTest < EppTestCase assert_no_emails end + def test_clears_force_delete_when_registrar_changed + Setting.request_confrimation_on_registrant_change_enabled = true + new_registrant = contacts(:william).becomes(Registrant) + @domain.schedule_force_delete(type: :fast_track) + assert_not_equal new_registrant, @domain.registrant + assert @domain.force_delete_scheduled? + + request_xml = <<-XML + + + + + + #{@domain.name} + + #{new_registrant.code} + + + + + + #{'test' * 2000} + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + + assert_epp_response :completed_successfully + assert_equal new_registrant, @domain.registrant + assert_not @domain.registrant_verification_asked? + refute @domain.force_delete_scheduled? + refute_includes @domain.statuses, DomainStatus::PENDING_UPDATE + assert_no_emails + end + def test_deactivates_domain_when_all_name_servers_are_removed assert @domain.active? assert_equal 2, @domain.nameservers.count @@ -287,13 +443,66 @@ class EppDomainUpdateBaseTest < EppTestCase XML - post epp_update_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } @domain.reload assert_epp_response :completed_successfully assert @domain.inactive? end + def test_update_domain_allows_add_of_client_hold + request_xml = <<-XML + + + + + + shop.test + + Test + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + assert_epp_response :completed_successfully + assert_includes(@domain.statuses, DomainStatus::CLIENT_HOLD) + end + + def test_update_domain_allows_remove_of_client_hold + @domain.update!(statuses: [DomainStatus::CLIENT_HOLD, DomainStatus::FORCE_DELETE, + DomainStatus::SERVER_RENEW_PROHIBITED, + DomainStatus::SERVER_TRANSFER_PROHIBITED]) + + request_xml = <<-XML + + + + + + shop.test + + Test + + + + + + XML + + post epp_update_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } + @domain.reload + assert_epp_response :completed_successfully + assert_not_includes(@domain.statuses, DomainStatus::CLIENT_HOLD) + end + private def assert_verification_and_notification_emails diff --git a/test/integration/epp/hello_test.rb b/test/integration/epp/hello_test.rb index c7d5356c2..b2e03c20b 100644 --- a/test/integration/epp/hello_test.rb +++ b/test/integration/epp/hello_test.rb @@ -9,7 +9,8 @@ class EppHelloTest < EppTestCase XML - get epp_hello_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=non-existent' + get epp_hello_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=non-existent' } response_xml = Nokogiri::XML(response.body) assert_equal 'EPP server (EIS)', response_xml.at_css('greeting > svID').text diff --git a/test/integration/epp/login/credentials_test.rb b/test/integration/epp/login/credentials_test.rb index e6cc7742b..a62579766 100644 --- a/test/integration/epp/login/credentials_test.rb +++ b/test/integration/epp/login/credentials_test.rb @@ -23,7 +23,8 @@ class EppLoginCredentialsTest < EppTestCase XML - post epp_login_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=new_session_id' } + post epp_login_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=new_session_id' } assert EppSession.find_by(session_id: 'new_session_id') assert_equal users(:api_bestnames), EppSession.find_by(session_id: 'new_session_id').user assert_epp_response :completed_successfully @@ -55,7 +56,8 @@ class EppLoginCredentialsTest < EppTestCase XML - post epp_login_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=any_random_string' + post epp_login_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=any_random_string' } assert_epp_response :authentication_error_server_closing_connection end diff --git a/test/integration/epp/login/password_change_test.rb b/test/integration/epp/login/password_change_test.rb index 4466248a8..3b1834406 100644 --- a/test/integration/epp/login/password_change_test.rb +++ b/test/integration/epp/login/password_change_test.rb @@ -24,7 +24,8 @@ class EppLoginPasswordChangeTest < EppTestCase XML - post epp_login_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=new_session_id' } + post epp_login_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=new_session_id' } assert_equal 'new-password', users(:api_bestnames).plain_text_password assert_epp_response :completed_successfully end diff --git a/test/integration/epp/login/session_limit_test.rb b/test/integration/epp/login/session_limit_test.rb index f68aac4e4..f1d83fe7b 100644 --- a/test/integration/epp/login/session_limit_test.rb +++ b/test/integration/epp/login/session_limit_test.rb @@ -14,7 +14,8 @@ class EppLoginSessionLimitTest < EppTestCase end assert_difference 'EppSession.count' do - post epp_login_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=new_session_id' } + post epp_login_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=new_session_id' } end assert_epp_response :completed_successfully end @@ -27,7 +28,8 @@ class EppLoginSessionLimitTest < EppTestCase end assert_no_difference 'EppSession.count' do - post epp_login_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=new_session_id' } + post epp_login_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=new_session_id' } end assert_epp_response :authentication_error_server_closing_connection end diff --git a/test/integration/epp/logout_test.rb b/test/integration/epp/logout_test.rb index a578246ae..62fa06ca9 100644 --- a/test/integration/epp/logout_test.rb +++ b/test/integration/epp/logout_test.rb @@ -2,22 +2,26 @@ require 'test_helper' class EppLogoutTest < EppTestCase def test_success_response - post epp_logout_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_logout_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :completed_successfully_ending_session end def test_ends_current_session - post epp_logout_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_logout_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_nil EppSession.find_by(session_id: 'api_bestnames') end def test_keeps_other_sessions_intact - post epp_logout_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + post epp_logout_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert EppSession.find_by(session_id: 'api_goodnames') end def test_anonymous_user - post epp_logout_path, { frame: request_xml }, { 'HTTP_COOKIE' => 'session=non-existent' } + post epp_logout_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=non-existent' } assert_epp_response :authorization_error end diff --git a/test/integration/epp/poll_test.rb b/test/integration/epp/poll_test.rb index 5ccd4258a..c08b0fd9a 100644 --- a/test/integration/epp/poll_test.rb +++ b/test/integration/epp/poll_test.rb @@ -15,7 +15,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } xml_doc = Nokogiri::XML(response.body) assert_epp_response :completed_successfully_ack_to_dequeue @@ -36,7 +37,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } xml_doc = Nokogiri::XML(response.body) namespace = 'https://epp.tld.ee/schema/changePoll-1.0.xsd' @@ -60,7 +62,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :completed_successfully_no_messages end @@ -77,7 +80,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } notification.reload xml_doc = Nokogiri::XML(response.body) @@ -98,7 +102,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } notification.reload assert notification.unread? @@ -114,7 +119,8 @@ class EppPollTest < EppTestCase XML - post epp_poll_path, { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + post epp_poll_path, params: { frame: request_xml }, + headers: { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_epp_response :object_does_not_exist end diff --git a/test/integration/registrant_area/contacts_test.rb b/test/integration/registrant_area/contacts_test.rb new file mode 100644 index 000000000..c906cd026 --- /dev/null +++ b/test/integration/registrant_area/contacts_test.rb @@ -0,0 +1,19 @@ +require 'test_helper' + +class RegistrantAreaContactsIntegrationTest < ApplicationIntegrationTest + setup do + @domain = domains(:shop) + @registrant = users(:registrant) + sign_in @registrant + end + + def test_can_view_other_domain_contacts + secondary_contact = contacts(:jane) + + visit registrant_domain_path(@domain) + assert_text secondary_contact.name + click_link secondary_contact.name + assert_text @domain.name + assert_text secondary_contact.email + end +end diff --git a/test/integration/registrant_area/domains_test.rb b/test/integration/registrant_area/domains_test.rb index 11709dd5b..d2ca1c775 100644 --- a/test/integration/registrant_area/domains_test.rb +++ b/test/integration/registrant_area/domains_test.rb @@ -10,7 +10,7 @@ class RegistrantAreaDomainsIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal "#{Mime[:csv]}; charset=utf-8", response.headers['Content-Type'] - assert_equal 'attachment; filename="domains.csv"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"domains.csv\"; filename*=UTF-8''domains.csv", response.headers['Content-Disposition'] assert_not_empty response.body end @@ -19,7 +19,7 @@ class RegistrantAreaDomainsIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal Mime[:pdf], response.headers['Content-Type'] - assert_equal 'attachment; filename="domains.pdf"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"domains.pdf\"; filename*=UTF-8''domains.pdf", response.headers['Content-Disposition'] assert_not_empty response.body end end diff --git a/test/integration/registrant_area/sign_in/id_card_test.rb b/test/integration/registrant_area/sign_in/id_card_test.rb index 68f0d408e..fe6c8a7ef 100644 --- a/test/integration/registrant_area/sign_in/id_card_test.rb +++ b/test/integration/registrant_area/sign_in/id_card_test.rb @@ -6,9 +6,9 @@ class RegistrantAreaIdCardSignInTest < ApplicationIntegrationTest end def test_succeeds - post_via_redirect registrant_id_card_sign_in_path, nil, - 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234', - 'SSL_CLIENT_I_DN_C' => 'US' + post registrant_id_card_sign_in_path, headers: { 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234', + 'SSL_CLIENT_I_DN_C' => 'US' } + follow_redirect! assert_response :ok assert_equal registrant_root_path, path @@ -16,7 +16,7 @@ class RegistrantAreaIdCardSignInTest < ApplicationIntegrationTest end def test_fails_when_certificate_is_absent - post_via_redirect registrant_id_card_sign_in_path, nil, 'SSL_CLIENT_S_DN_CN' => '' + post registrant_id_card_sign_in_path, headers: { 'SSL_CLIENT_S_DN_CN' => '' } assert_response :ok assert_equal registrant_id_card_sign_in_path, path diff --git a/test/integration/registrar_area/contacts_test.rb b/test/integration/registrar_area/contacts_test.rb index 2597518b1..a8e50aafa 100644 --- a/test/integration/registrar_area/contacts_test.rb +++ b/test/integration/registrar_area/contacts_test.rb @@ -10,7 +10,7 @@ class RegistrarAreaContactsIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal "#{Mime[:csv]}; charset=utf-8", response.headers['Content-Type'] - assert_equal 'attachment; filename="contacts.csv"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"contacts.csv\"; filename*=UTF-8''contacts.csv", response.headers['Content-Disposition'] assert_not_empty response.body end @@ -19,7 +19,7 @@ class RegistrarAreaContactsIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal Mime[:pdf], response.headers['Content-Type'] - assert_equal 'attachment; filename="contacts.pdf"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"contacts.pdf\"; filename*=UTF-8''contacts.pdf", response.headers['Content-Disposition'] assert_not_empty response.body end end diff --git a/test/integration/registrar_area/domains_test.rb b/test/integration/registrar_area/domains_test.rb index eaa43e674..1a4e0534c 100644 --- a/test/integration/registrar_area/domains_test.rb +++ b/test/integration/registrar_area/domains_test.rb @@ -13,7 +13,7 @@ class RegistrarAreaDomainsIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal "#{Mime[:csv]}; charset=utf-8", response.headers['Content-Type'] - assert_equal %(attachment; filename="Domains_#{l(now, format: :filename)}.csv"), + assert_equal %(attachment; filename="Domains_#{l(now, format: :filename)}.csv"; filename*=UTF-8''Domains_#{l(now, format: :filename)}.csv), response.headers['Content-Disposition'] assert_not_empty response.body end diff --git a/test/integration/registrar_area/invoices/payment_callback_test.rb b/test/integration/registrar_area/invoices/payment_callback_test.rb index 985b93914..94ca6e373 100644 --- a/test/integration/registrar_area/invoices/payment_callback_test.rb +++ b/test/integration/registrar_area/invoices/payment_callback_test.rb @@ -6,34 +6,40 @@ class PaymentCallbackTest < ApplicationIntegrationTest @user = users(:api_bestnames) sign_in @user + + @payment_order = payment_orders(:everypay_issued) + @invoice = invoices(:one) + @invoice.update!(account_activity: nil, total: 12) end def test_every_pay_callback_returns_status_200 - invoice = payable_invoice - assert_matching_bank_transaction_exists(invoice) - - request_params = every_pay_request_params.merge(invoice_id: invoice.id) - post "/registrar/pay/callback/every_pay", request_params + request_params = every_pay_request_params + post "/registrar/pay/callback/#{@payment_order.id}", params: request_params assert_response :ok end + def test_invoice_is_marked_as_paid + request_params = every_pay_request_params + post "/registrar/pay/callback/#{@payment_order.id}", params: request_params + + assert @payment_order.invoice.paid? + end + + def failure_log_is_created_if_unsuccessful_payment + request_params = every_pay_request_params.dup + request_params['payment_state'] = 'cancelled' + request_params['transaction_result'] = 'failed' + + post "/registrar/pay/callback/#{@payment_order.id}", params: request_params + + @payment_order.reload + assert @payment_order.cancelled? + assert_includes @payment_order.notes, 'Payment state: cancelled' + end + private - def payable_invoice - invoice = invoices(:one) - invoice.update!(account_activity: nil) - invoice - end - - def assert_matching_bank_transaction_exists(invoice) - assert BankTransaction.find_by( - description: invoice.order, - currency: invoice.currency, - iban: invoice.seller_iban - ), 'Matching bank transaction should exist' - end - def every_pay_request_params { nonce: "392f2d7748bc8cb0d14f263ebb7b8932", @@ -56,4 +62,4 @@ class PaymentCallbackTest < ApplicationIntegrationTest payment_method: "every_pay" } end -end \ No newline at end of file +end diff --git a/test/integration/registrar_area/invoices/payment_return_test.rb b/test/integration/registrar_area/invoices/payment_return_test.rb index b6317a0d0..a4adb8160 100644 --- a/test/integration/registrar_area/invoices/payment_return_test.rb +++ b/test/integration/registrar_area/invoices/payment_return_test.rb @@ -8,6 +8,9 @@ class PaymentReturnTest < ApplicationIntegrationTest sign_in @user @invoice = invoices(:one) + @invoice.update!(account_activity: nil, total: 12) + @everypay_order = payment_orders(:everypay_issued) + @banklink_order = payment_orders(:banklink_issued) end def every_pay_request_params @@ -57,33 +60,78 @@ class PaymentReturnTest < ApplicationIntegrationTest } end - def test_every_pay_return_creates_activity_redirects_to_invoice_path - request_params = every_pay_request_params.merge(invoice_id: @invoice.id) + def test_successful_bank_payment_marks_invoice_as_paid + @invoice.update!(account_activity: nil) + request_params = bank_link_request_params - post "/registrar/pay/return/every_pay", request_params + post "/registrar/pay/return/#{@banklink_order.id}", params: request_params + + @banklink_order.reload + assert @banklink_order.invoice.paid? + end + + def test_every_pay_return_creates_activity_redirects_to_invoice_path + request_params = every_pay_request_params + + post "/registrar/pay/return/#{@everypay_order.id}", params: request_params assert_equal(302, response.status) assert_redirected_to(registrar_invoice_path(@invoice)) end - def test_Every_Pay_return_raises_RecordNotFound - request_params = every_pay_request_params.merge(invoice_id: "178907") + def test_every_pay_return_raises_record_not_found + request_params = every_pay_request_params assert_raises(ActiveRecord::RecordNotFound) do - post "/registrar/pay/return/every_pay", request_params + post '/registrar/pay/return/123456', params: request_params end end def test_bank_link_return_redirects_to_invoice_paths - request_params = bank_link_request_params.merge(invoice_id: @invoice.id) + request_params = bank_link_request_params - post "/registrar/pay/return/seb", request_params + post "/registrar/pay/return/#{@banklink_order.id}", params: request_params assert_equal(302, response.status) assert_redirected_to(registrar_invoice_path(@invoice)) end def test_bank_link_return - request_params = bank_link_request_params.merge(invoice_id: "178907") + request_params = bank_link_request_params assert_raises(ActiveRecord::RecordNotFound) do - post "/registrar/pay/return/seb", request_params + post '/registrar/pay/return/123456', params: request_params end end + + def test_marks_as_paid_and_adds_notes_if_failed_to_bind + request_params = bank_link_request_params + + post "/registrar/pay/return/#{@banklink_order.id}", params: request_params + post "/registrar/pay/return/#{@banklink_order.id}", params: request_params + @banklink_order.reload + + assert @banklink_order.notes.present? + assert @banklink_order.paid? + assert_includes @banklink_order.notes, 'Failed to bind' + end + + def test_failed_bank_link_payment_creates_brief_error_explanation + request_params = bank_link_request_params.dup + request_params['VK_SERVICE'] = '1911' + + post "/registrar/pay/return/#{@banklink_order.id}", params: request_params + + @banklink_order.reload + + assert_includes @banklink_order.notes, 'Bank responded with code 1911' + end + + def test_failed_every_pay_payment_creates_brief_error_explanation + request_params = every_pay_request_params.dup + request_params['payment_state'] = 'cancelled' + request_params['transaction_result'] = 'failed' + + post "/registrar/pay/return/#{@everypay_order.id}", params: request_params + + @everypay_order.reload + + assert_includes @everypay_order.notes, 'Payment state: cancelled' + end end diff --git a/test/integration/registrar_area/invoices_test.rb b/test/integration/registrar_area/invoices_test.rb index 1f43a5287..91c6afbd8 100644 --- a/test/integration/registrar_area/invoices_test.rb +++ b/test/integration/registrar_area/invoices_test.rb @@ -13,7 +13,7 @@ class RegistrarAreaInvoicesIntegrationTest < ApplicationIntegrationTest assert_response :ok assert_equal 'application/pdf', response.headers['Content-Type'] - assert_equal 'attachment; filename="invoice-1.pdf"', response.headers['Content-Disposition'] + assert_equal "attachment; filename=\"invoice-1.pdf\"; filename*=UTF-8''invoice-1.pdf", response.headers['Content-Disposition'] assert_not_empty response.body end -end \ No newline at end of file +end diff --git a/test/integration/registrar_area/settings/balance_auto_reload_test.rb b/test/integration/registrar_area/settings/balance_auto_reload_test.rb index 2c89630ea..1a2c3f835 100644 --- a/test/integration/registrar_area/settings/balance_auto_reload_test.rb +++ b/test/integration/registrar_area/settings/balance_auto_reload_test.rb @@ -13,8 +13,8 @@ class RegistrarAreaSettingsBalanceAutoReloadIntegrationTest < ActionDispatch::In threshold = 10 assert_nil @registrar.settings['balance_auto_reload'] - patch registrar_settings_balance_auto_reload_path, { type: { amount: amount, - threshold: threshold } } + patch registrar_settings_balance_auto_reload_path, params: { type: { amount: amount, + threshold: threshold } } @registrar.reload assert_equal amount, @registrar.settings['balance_auto_reload']['type']['amount'] diff --git a/test/integration/registrar_area/sign_in/id_card_test.rb b/test/integration/registrar_area/sign_in/id_card_test.rb index 0a38e4105..1441c90ca 100644 --- a/test/integration/registrar_area/sign_in/id_card_test.rb +++ b/test/integration/registrar_area/sign_in/id_card_test.rb @@ -13,7 +13,8 @@ class RegistrarAreaIdCardSignInTest < ApplicationIntegrationTest def test_signs_in_a_user_when_id_card_owner_is_found assert_equal '1234', @user.identity_code - post_via_redirect registrar_id_card_sign_in_path, nil, 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234' + post registrar_id_card_sign_in_path, headers: { 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234' } + follow_redirect! assert_response :ok assert_equal registrar_root_path, path @@ -21,8 +22,8 @@ class RegistrarAreaIdCardSignInTest < ApplicationIntegrationTest end def test_does_not_sign_in_a_user_when_id_card_owner_is_not_found - post_via_redirect registrar_id_card_sign_in_path, nil, - 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,unacceptable-personal-code' + post registrar_id_card_sign_in_path, + headers: { 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,unacceptable-personal-code' } assert_nil controller.current_registrar_user assert_equal registrar_id_card_sign_in_path, path @@ -36,8 +37,8 @@ class RegistrarAreaIdCardSignInTest < ApplicationIntegrationTest Setting.registrar_ip_whitelist_enabled = true - post registrar_id_card_sign_in_path, nil, 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234', - 'REMOTE_ADDR' => '127.0.0.2' + post registrar_id_card_sign_in_path, headers: { 'SSL_CLIENT_S_DN_CN' => 'DOE,JOHN,1234', + 'REMOTE_ADDR' => '127.0.0.2' } assert_equal registrar_id_card_sign_in_path, path assert_equal 'Access denied from IP 127.0.0.2', response.body @@ -47,7 +48,7 @@ class RegistrarAreaIdCardSignInTest < ApplicationIntegrationTest end def test_does_not_sign_in_a_user_when_certificate_is_absent - post_via_redirect registrar_id_card_sign_in_path, nil, 'SSL_CLIENT_S_DN_CN' => '' + post registrar_id_card_sign_in_path, headers: { 'SSL_CLIENT_S_DN_CN' => '' } assert_nil controller.current_registrar_user assert_equal registrar_id_card_sign_in_path, path diff --git a/test/integration/repp/auctions_test.rb b/test/integration/repp/auctions_test.rb new file mode 100644 index 000000000..145e5d17a --- /dev/null +++ b/test/integration/repp/auctions_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class ReppV1AuctionsTest < ActionDispatch::IntegrationTest + setup do + @auction = auctions(:one) + + @auction.update!(uuid: '1b3ee442-e8fe-4922-9492-8fcb9dccc69c', + domain: 'auction.test', + status: Auction.statuses[:started]) + end + + def test_get_index + get repp_v1_auctions_path + response_json = JSON.parse(response.body, symbolize_names: true) + + assert response_json[:count] == 1 + + expected_response = [{ domain_name: @auction.domain, + punycode_domain_name: @auction.domain }] + + assert_equal expected_response, response_json[:auctions] + end +end diff --git a/test/integration/repp/retained_domains_test.rb b/test/integration/repp/retained_domains_test.rb new file mode 100644 index 000000000..1c9f49f58 --- /dev/null +++ b/test/integration/repp/retained_domains_test.rb @@ -0,0 +1,117 @@ +require 'test_helper' + +class ReppV1RetainedDomainsTest < ActionDispatch::IntegrationTest + # Uses magical fixtures, will fail once fixtures inside are changed: + # test/fixtures/blocked_domains.yml + # test/fixtures/reserved_domains.yml + + def test_get_index + get repp_v1_retained_domains_path + response_json = JSON.parse(response.body, symbolize_names: true) + + assert response_json[:count] == 3 + + expected_objects = [{ name: 'blocked.test', + status: 'blocked', + punycode_name: 'blocked.test' }, + { name: 'blockedäöüõ.test', + status: 'blocked', + punycode_name: 'xn--blocked-cxa7mj0e.test' }, + { name: 'reserved.test', + status: 'reserved', + punycode_name: 'reserved.test' }] + + assert_equal response_json[:domains], expected_objects + end + + def test_get_index_with_type_parameter + get repp_v1_retained_domains_path({ 'type' => 'reserved' }) + response_json = JSON.parse(response.body, symbolize_names: true) + + assert response_json[:count] == 1 + + expected_objects = [{ name: 'reserved.test', + status: 'reserved', + punycode_name: 'reserved.test' }] + + assert_equal response_json[:domains], expected_objects + end + + def test_get_index_disputed_type + dispute = Dispute.new(domain_name: 'disputed.test', starts_at: Time.zone.today, password: 'disputepw') + dispute.save + + get repp_v1_retained_domains_path({ 'type' => 'disputed' }) + response_json = JSON.parse(response.body, symbolize_names: true) + + assert response_json[:count] == 1 + + expected_objects = [{ name: 'disputed.test', + status: 'disputed', + punycode_name: 'disputed.test' }] + + assert_equal response_json[:domains], expected_objects + end + + # A disputed domain can be also reserved, and according + # to business rules it should appear on the list twice. + def test_domain_can_appear_twice_if_it_is_disputed_and_reserved + dispute = Dispute.new(domain_name: 'reserved.test', starts_at: Time.zone.today, password: 'disputepw') + dispute.save + + get repp_v1_retained_domains_path + response_json = JSON.parse(response.body, symbolize_names: true) + + assert response_json[:count] == 4 + + expected_objects = [{ name: 'blocked.test', + status: 'blocked', + punycode_name: 'blocked.test' }, + { name: 'blockedäöüõ.test', + status: 'blocked', + punycode_name: 'xn--blocked-cxa7mj0e.test' }, + { name: 'reserved.test', + status: 'reserved', + punycode_name: 'reserved.test' }, + { name: 'reserved.test', + status: 'disputed', + punycode_name: 'reserved.test' }] + + assert_equal response_json[:domains], expected_objects + end + + def test_etags_cache + get repp_v1_retained_domains_path({ 'type' => 'reserved' }) + etag = response.headers['ETag'] + + get repp_v1_retained_domains_path({ 'type' => 'reserved' }), + headers: { 'If-None-Match' => etag } + + assert_equal response.status, 304 + assert_equal response.body, '' + end + + def test_etags_cache_valid_for_type_only + get repp_v1_retained_domains_path({ 'type' => 'blocked' }) + etag = response.headers['ETag'] + + get repp_v1_retained_domains_path, headers: { 'If-None-Match' => etag } + + assert_equal response.status, 200 + response_json = JSON.parse(response.body, symbolize_names: true) + assert response_json[:count] == 3 + end + + def test_cors_preflight + process :options, repp_v1_retained_domains_path, headers: { 'Origin' => 'https://example.com' } + + assert_equal('https://example.com', response.headers['Access-Control-Allow-Origin']) + assert_equal('POST, GET, PUT, PATCH, DELETE, OPTIONS', + response.headers['Access-Control-Allow-Methods']) + assert_equal('Origin, Content-Type, Accept, Authorization, Token, Auth-Token, Email, ' \ + 'X-User-Token, X-User-Email', + response.headers['Access-Control-Allow-Headers']) + assert_equal('3600', response.headers['Access-Control-Max-Age']) + assert_equal('', response.body) + end +end diff --git a/test/integration/tasks/data_migrations/regenerate_registrar_reference_numbers_test.rb b/test/integration/tasks/data_migrations/regenerate_registrar_reference_numbers_test.rb deleted file mode 100644 index 946c6b898..000000000 --- a/test/integration/tasks/data_migrations/regenerate_registrar_reference_numbers_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'test_helper' - -class RegenerateRegistrarReferenceNumbersTaskTest < ActiveSupport::TestCase - def test_regenerates_registrar_reference_numbers_to_estonian_format - registrar = registrars(:bestnames) - registrar.update_column(:reference_no, 'RF1111') - - capture_io { run_task } - registrar.reload - - assert_not registrar.reference_no.start_with?('RF') - end - - def test_bypasses_registrar_validation - registrar = registrars(:invalid) - registrar.update_column(:reference_no, 'RF1111') - assert registrar.invalid? - - capture_io { run_task } - registrar.reload - - assert_not registrar.reference_no.start_with?('RF') - end - - def test_does_not_regenerate_when_the_task_is_run_again - registrar = registrars(:bestnames) - registrar.update!(reference_no: '1111') - - capture_io { run_task } - registrar.reload - - assert_equal '1111', registrar.reference_no - end - - def test_keeps_iso_reference_number_on_the_invoice_unchanged - registrar = registrars(:bestnames) - registrar.update_column(:reference_no, 'RF1111') - invoice = invoices(:one) - invoice.update!(reference_no: 'RF2222') - - capture_io { run_task } - invoice.reload - - assert_equal 'RF2222', invoice.reference_no - end - - def test_output - registrar = registrars(:bestnames) - registrar.update_column(:reference_no, 'RF1111') - - assert_output "Registrars processed: 1\n" do - run_task - end - end - - private - - def run_task - Rake::Task['data_migrations:regenerate_registrar_reference_numbers'].execute - end -end diff --git a/test/jobs/directo_invoice_forward_job_test.rb b/test/jobs/directo_invoice_forward_job_test.rb new file mode 100644 index 000000000..57b1759ff --- /dev/null +++ b/test/jobs/directo_invoice_forward_job_test.rb @@ -0,0 +1,155 @@ +require "test_helper" + +class DirectoInvoiceForwardJobTest < ActiveSupport::TestCase + setup do + @invoice = invoices(:one) + @user = registrars(:bestnames) + travel_to Time.zone.parse('2010-08-06') + end + + def teardown + Setting.clear_cache + Setting.directo_monthly_number_min = 309901 + Setting.directo_monthly_number_max = 309999 + Setting.directo_monthly_number_last = 309901 + end + + def test_directo_json_sends_customer_as_hash + @invoice.update!(buyer_country_code: @user.address_country_code) + + json_output = @invoice.as_directo_json + assert json_output['customer'].is_a? Hash + assert_equal @user.accounting_customer_code, json_output['customer']['code'] + assert_equal @user.address_country_code, json_output['customer']['destination'] + end + + def test_xml_is_include_transaction_date + @invoice.update(total: @invoice.account_activity.bank_transaction.sum) + @invoice.account_activity.bank_transaction.update(paid_at: Time.zone.now) + + response = <<-XML + + + + + XML + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + request.body.include? 'TransactionDate' + end.to_return(status: 200, body: response) + + assert_nothing_raised do + DirectoInvoiceForwardJob.run(monthly: false, dry: false) + end + + assert_not_empty @invoice.directo_records.first.request + end + + def test_fails_if_directo_bounds_exceedable + activity = account_activities(:one) + price = billing_prices(:create_one_year) + activity.update!(activity_type: 'create', price: price) + + Setting.directo_monthly_number_max = 30991 + + assert_raises 'RuntimeError' do + DirectoInvoiceForwardJob.run(monthly: true, dry: false) + end + end + + def test_monthly_summary_is_delivered_in_estonian + activity = account_activities(:one) + price = billing_prices(:create_one_year) + activity.update!(activity_type: 'create', price: price) + @user.update(language: 'et') + + response = <<-XML + + + + + XML + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + body = CGI.unescape(request.body) + + (body.include? '.test registreerimine: 1 aasta(t)') && + (body.include? 'Domeenide ettemaks') && + (body.include? '309902') + end.to_return(status: 200, body: response) + + assert_difference 'Setting.directo_monthly_number_last' do + DirectoInvoiceForwardJob.run(monthly: true, dry: false) + end + end + + def test_monthly_summary_is_delivered_in_english + activity = account_activities(:one) + price = billing_prices(:create_one_year) + activity.update(activity_type: 'create', price: price) + @user.update(language: 'en') + + response = <<-XML + + + + + XML + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + body = CGI.unescape(request.body) + (body.include? 'test registration') && + (body.include? 'Domains prepayment') && + (body.include? '309902') + end.to_return(status: 200, body: response) + + assert_difference 'Setting.directo_monthly_number_last' do + DirectoInvoiceForwardJob.run(monthly: true, dry: false) + end + end + + def test_multi_year_purchases_have_duration_assigned + activity = account_activities(:one) + price = billing_prices(:create_one_year) + price.update(duration: '3 years') + activity.update(activity_type: 'create', price: price) + + response = <<-XML + + + + + XML + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + body = CGI.unescape(request.body) + (body.include? 'StartDate') && (body.include? 'EndDate') + end.to_return(status: 200, body: response) + + assert_difference 'Setting.directo_monthly_number_last' do + DirectoInvoiceForwardJob.run(monthly: true, dry: false) + end + end + + def test_monthly_duration_products_are_present_in_summary + activity = account_activities(:one) + price = billing_prices(:create_one_month) + activity.update(activity_type: 'create', price: price) + + response = <<-XML + + + + + XML + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + body = CGI.unescape(request.body) + body.include? 'month(s)' + end.to_return(status: 200, body: response) + + assert_difference 'Setting.directo_monthly_number_last' do + DirectoInvoiceForwardJob.run(monthly: true, dry: false) + end + end +end diff --git a/test/jobs/dispute_status_update_job_test.rb b/test/jobs/dispute_status_update_job_test.rb new file mode 100644 index 000000000..e70e58c04 --- /dev/null +++ b/test/jobs/dispute_status_update_job_test.rb @@ -0,0 +1,70 @@ +require "test_helper" + +class DisputeStatusUpdateJobTest < ActiveSupport::TestCase + setup do + travel_to Time.zone.parse('2010-10-05') + @logger = Rails.logger + end + + def test_nothing_is_raised + assert_nothing_raised do + DisputeStatusUpdateJob.run(logger: @logger) + end + end + + def test_whois_data_added_when_dispute_activated + dispute = disputes(:future) + DisputeStatusUpdateJob.run(logger: @logger) + + whois_record = Whois::Record.find_by(name: dispute.domain_name) + assert whois_record.present? + assert_includes whois_record.json['status'], 'disputed' + end + + def test_on_expiry_unregistered_domain_is_sent_to_auction + dispute = disputes(:active) + dispute.update!(starts_at: Time.zone.today - 3.years - 1.day) + + DisputeStatusUpdateJob.run(logger: @logger) + dispute.reload + + assert dispute.closed + + whois_record = Whois::Record.find_by(name: dispute.domain_name) + assert_equal ['AtAuction'], whois_record.json['status'] + end + + def test_registered_domain_whois_data_is_added + Dispute.create(domain_name: 'shop.test', starts_at: '2010-07-05') + travel_to Time.zone.parse('2010-07-05') + DisputeStatusUpdateJob.run(logger: @logger) + + whois_record = Whois::Record.find_by(name: 'shop.test') + assert_includes whois_record.json['status'], 'disputed' + end + + def test_registered_domain_whois_data_is_removed + travel_to Time.zone.parse('2010-07-05') + + domain = domains(:shop) + domain.update(valid_to: Time.zone.parse('2015-07-05').to_s(:db), + outzone_at: Time.zone.parse('2015-07-06').to_s(:db), + delete_date: nil, + force_delete_date: nil) + + # Dispute status is added automatically if starts_at is not in future + Dispute.create(domain_name: 'shop.test', starts_at: Time.zone.parse('2010-07-05')) + domain.reload + + whois_record = Whois::Record.find_by(name: 'shop.test') + assert_includes whois_record.json['status'], 'disputed' + + # Dispute status is removed night time day after it's ended + travel_to Time.zone.parse('2010-07-05') + 3.years + 1.day + + DisputeStatusUpdateJob.run(logger: @logger) + + whois_record.reload + assert_not whois_record.json['status'].include? 'disputed' + end +end diff --git a/test/jobs/domain_delete_confirm_job_test.rb b/test/jobs/domain_delete_confirm_job_test.rb index 51af58c24..b999bd3c7 100644 --- a/test/jobs/domain_delete_confirm_job_test.rb +++ b/test/jobs/domain_delete_confirm_job_test.rb @@ -1,17 +1,11 @@ require "test_helper" class DomainDeleteConfirmJobTest < ActiveSupport::TestCase - def setup - super - + setup do + @legal_doc_path = 'test/fixtures/files/legaldoc.pdf' @domain = domains(:shop) @new_registrant = contacts(:william) @user = users(:api_bestnames) - - @domain.update!(pending_json: { new_registrant_id: @new_registrant.id, - new_registrant_name: @new_registrant.name, - new_registrant_email: @new_registrant.email, - current_user_id: @user.id }) end def teardown @@ -19,6 +13,11 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase end def test_rejected_registrant_verification_notifies_registrar + @domain.update!(pending_json: { new_registrant_id: @new_registrant.id, + new_registrant_name: @new_registrant.name, + new_registrant_email: @new_registrant.email, + current_user_id: @user.id }) + DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) last_registrar_notification = @domain.registrar.notifications.last @@ -27,10 +26,57 @@ class DomainDeleteConfirmJobTest < ActiveSupport::TestCase end def test_accepted_registrant_verification_notifies_registrar + @domain.update!(pending_json: { new_registrant_id: @new_registrant.id, + new_registrant_name: @new_registrant.name, + new_registrant_email: @new_registrant.email, + current_user_id: @user.id }) + DomainDeleteConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) last_registrar_notification = @domain.registrar.notifications.last assert_equal(last_registrar_notification.attached_obj_id, @domain.id) assert_equal(last_registrar_notification.text, 'Registrant confirmed domain deletion: shop.test') end + + def test_marks_domain_as_pending_delete_after_acceptance + epp_xml = "\n\n \n \n" \ + " \n #{@domain.name}\n \n \n \n" \ + " \n #{@legal_doc_path}\n" \ + " \n \n 20alla-1594212240\n \n\n" + + @domain.registrant_verification_asked!(epp_xml, @user.id) + @domain.pending_delete! + @domain.reload + + 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) + @domain.reload + + assert @domain.statuses.include? DomainStatus::PENDING_DELETE + assert @domain.statuses.include? DomainStatus::SERVER_HOLD + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + end + + def test_clears_pending_flags_after_delete_denial + epp_xml = "\n\n \n \n" \ + " \n #{@domain.name}\n \n \n \n" \ + " \n #{@legal_doc_path}\n" \ + " \n \n 20alla-1594212240\n \n\n" + + @domain.registrant_verification_asked!(epp_xml, @user.id) + @domain.pending_delete! + @domain.reload + + 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) + @domain.reload + + assert_equal ['ok'], @domain.statuses + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + end end diff --git a/test/jobs/domain_update_confirm_job_test.rb b/test/jobs/domain_update_confirm_job_test.rb index 070b5d5f7..59bbf758d 100644 --- a/test/jobs/domain_update_confirm_job_test.rb +++ b/test/jobs/domain_update_confirm_job_test.rb @@ -7,6 +7,7 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase @domain = domains(:shop) @new_registrant = contacts(:william) @user = users(:api_bestnames) + @legal_doc_path = 'test/fixtures/files/legaldoc.pdf' @domain.update!(pending_json: { new_registrant_id: @new_registrant.id, new_registrant_name: @new_registrant.name, @@ -33,4 +34,34 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase assert_equal(last_registrar_notification.attached_obj_id, @domain.id) assert_equal(last_registrar_notification.text, 'Registrant confirmed domain update: shop.test') end + + def test_changes_domain_registrant_after_approval + 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.reload + DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::CONFIRMED) + @domain.reload + + assert_equal @domain.registrant.code, @new_registrant.code + end + + def test_clears_pending_update_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) + + DomainUpdateConfirmJob.enqueue(@domain.id, RegistrantVerification::REJECTED) + @domain.reload + + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION + assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE + end end diff --git a/test/jobs/regeneate_subzone_whoises_job_test.rb b/test/jobs/regeneate_subzone_whoises_job_test.rb new file mode 100644 index 000000000..745c2392c --- /dev/null +++ b/test/jobs/regeneate_subzone_whoises_job_test.rb @@ -0,0 +1,18 @@ +require 'test_helper' + +class RegenerateSubzoneWhoisesJobTest < ActiveSupport::TestCase + def test_regenerates_whois_data_only_for_subzones + subzone = dns_zones(:one).dup + subzone.origin = 'subzone.test' + subzone.save + + Whois::Record.where(name: subzone.origin).destroy_all + Whois::Record.where(name: dns_zones(:one)).destroy_all + assert_nil Whois::Record.find_by(name: subzone.origin) + assert_nil Whois::Record.find_by(name: dns_zones(:one).origin) + + RegenerateSubzoneWhoisesJob.run + assert Whois::Record.find_by(name: subzone.origin) + assert_nil Whois::Record.find_by(name: dns_zones(:one).origin) + end +end diff --git a/test/jobs/send_e_invoice_job_test.rb b/test/jobs/send_e_invoice_job_test.rb new file mode 100644 index 000000000..384479e92 --- /dev/null +++ b/test/jobs/send_e_invoice_job_test.rb @@ -0,0 +1,47 @@ +require 'test_helper' + +class SendEInvoiceJobTest < ActiveSupport::TestCase + + def teardown + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + end + + def test_if_invoice_is_sended + @invoice = invoices(:one) + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + + assert_nothing_raised do + SendEInvoiceJob.enqueue(@invoice.id) + end + @invoice.reload + + assert_not @invoice.e_invoice_sent_at.blank? + assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count + end + + def test_if_invoice_sending_retries + @invoice = invoices(:one) + provider_config = { password: nil, + test_mode: true } + EInvoice.provider = EInvoice::Providers::OmnivaProvider.new(provider_config) + stub_request(:get, "https://testfinance.post.ee/finance/erp/erpServices.wsdl").to_timeout + + assert_raise HTTPClient::TimeoutError do + SendEInvoiceJob.enqueue(@invoice.id) + end + assert @invoicee_invoice_sent_at.blank? + + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + + assert_nothing_raised do + SendEInvoiceJob.enqueue(@invoice.id) + end + @invoice.reload + + assert_not @invoice.e_invoice_sent_at.blank? + assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count + end +end diff --git a/test/jobs/verify_emails_job_test.rb b/test/jobs/verify_emails_job_test.rb new file mode 100644 index 000000000..f55a474db --- /dev/null +++ b/test/jobs/verify_emails_job_test.rb @@ -0,0 +1,59 @@ +require "test_helper" + +class VerifyEmailsJobTest < ActiveSupport::TestCase + def setup + @contact = contacts(:john) + @invalid_contact = contacts(:invalid_email) + @contact_verification = @contact.email_verification + @invalid_contact_verification = @invalid_contact.email_verification + + @default_whitelist = Truemail.configure.whitelisted_domains + @default_blacklist = Truemail.configure.blacklisted_domains + Truemail.configure.whitelisted_domains = whitelisted_domains + Truemail.configure.blacklisted_domains = blacklisted_domains + end + + def teardown + Truemail.configure.whitelisted_domains = @default_whitelist + Truemail.configure.blacklisted_domains = @default_blacklist + end + + def domain(email) + Mail::Address.new(email).domain + rescue Mail::Field::IncompleteParseError + nil + end + + def whitelisted_domains + [domain(@contact.email)].reject(&:blank?) + end + + def blacklisted_domains + [domain(@invalid_contact.email)].reject(&:blank?) + end + + def test_job_checks_if_email_valid + VerifyEmailsJob.run(@contact_verification.id) + @contact_verification.reload + + assert @contact_verification.success + end + + def test_job_checks_does_not_run_if_recent + old_verified_at = Time.zone.now - 10.days + @contact_verification.update(success: true, verified_at: old_verified_at) + assert @contact_verification.recently_verified? + + VerifyEmailsJob.run(@contact_verification.id) + @contact_verification.reload + + assert_in_delta @contact_verification.verified_at.to_i, old_verified_at.to_i, 1 + end + + def test_job_checks_if_email_invalid + VerifyEmailsJob.run(@invalid_contact_verification.id) + @contact_verification.reload + + refute @contact_verification.success + end +end diff --git a/test/learning/paper_trail_test.rb b/test/learning/paper_trail_test.rb index d4c76b026..cecb4f095 100644 --- a/test/learning/paper_trail_test.rb +++ b/test/learning/paper_trail_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class Post < ActiveRecord::Base +class Post < ApplicationRecord has_paper_trail end @@ -9,7 +9,7 @@ class PaperTrailLearningTest < ActiveSupport::TestCase ActiveRecord::Base.connection.create_table :posts do |t| t.string :title - # Otherwise `touch_with_version` fails silently + # Otherwise `touch` fails silently t.datetime :updated_at end end @@ -21,6 +21,25 @@ class PaperTrailLearningTest < ActiveSupport::TestCase assert_respond_to @record.versions.first, :item_id end + def test_returns_version_count_on_domains + @domain = domains(:airport) + @domain.save + + assert_equal 1, @domain.versions.count + + @domain.name = 'domain.test' + @domain.save! + assert_equal 2, @domain.versions.count + end + + def test_returns_version_count_on_users + @user = users(:registrant) + + @user.email = 'aaa@bbb.com' + @user.save! + assert_equal 1, @user.versions.count + end + def test_creates_new_version_upon_update @record = Post.create!(title: 'old title') original_record = @record.clone @@ -36,11 +55,11 @@ class PaperTrailLearningTest < ActiveSupport::TestCase assert_equal 'update', version.event end - def test_touch_with_version + def test_touch @record = Post.create!(title: 'any') - + assert_difference -> { @record.versions.size } do - @record.touch_with_version + @record.touch end end -end \ No newline at end of file +end diff --git a/test/lib/deserializers/xml/contact_test.rb b/test/lib/deserializers/xml/contact_test.rb new file mode 100644 index 000000000..4621efeb2 --- /dev/null +++ b/test/lib/deserializers/xml/contact_test.rb @@ -0,0 +1,114 @@ +require 'test_helper' +require 'deserializers/xml/contact' + +class DeserializersXmlContactTest < ActiveSupport::TestCase + def test_trims_empty_values + xml_string = <<-XML + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Contact.new(nokogiri_frame) + assert_equal instance.call, {} + end + + def test_handles_update + xml_string = <<-XML + + + + + + john-001 + + + new name + Org + + +123.4 + new-email@inbox.test + + + + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Contact.new(nokogiri_frame) + assert_equal instance.call, { name: 'new name', + org_name: 'Org', + email: 'new-email@inbox.test', + phone: '+123.4' } + end + + def test_handles_create + name = 'new' + email = 'new@registrar.test' + phone = '+1.2' + + xml_string = <<-XML + + + + + + + #{name} + + #{phone} + #{email} + + + + + any + + + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Contact.new(nokogiri_frame) + assert_equal instance.call, { name: 'new', email: 'new@registrar.test', phone: '+1.2' } + end + + def test_handles_statuses + xml_string = <<-XML + + + + + + john-001 + + + new name + + +123.4 + new-email@inbox.test + + + Payment overdue. + + + + + + + + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Contact.new(nokogiri_frame) + assert_equal instance.call, { name: 'new name', + email: 'new-email@inbox.test', + phone: '+123.4', + statuses_to_add: ['clientDeleteProhibited', + 'clientUpdateProhibited'], + statuses_to_remove: ['pendingDelete'] + } + end +end diff --git a/test/lib/deserializers/xml/ident_test.rb b/test/lib/deserializers/xml/ident_test.rb new file mode 100644 index 000000000..beff7aef5 --- /dev/null +++ b/test/lib/deserializers/xml/ident_test.rb @@ -0,0 +1,95 @@ +require 'test_helper' +require 'deserializers/xml/ident' + +class DeserializersXmlIdentTest < ActiveSupport::TestCase + def test_returns_empty_hash_when_not_present + xml_string = <<-XML + + + + + + john-001 + + + new name + + +123.4 + new-email@inbox.test + + + + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Ident.new(nokogiri_frame) + assert_equal instance.call, {} + end + + def test_returns_empty_hash_when_not_valid + xml_string = <<-XML + + + + + + FIRST0:SH2027223711 + + wrong password + + + + + + 37605030299 + dGVzdCBmYWlsCg== + + + ABC-12345 + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Ident.new(nokogiri_frame) + assert_equal instance.call, {} + end + + def test_returns_complete_hash_when_valid + xml_string = <<-XML + + + + + + FIRST0:SH2027223711 + + wrong password + + + + + + 37605030299 + dGVzdCBmYWlsCg== + + + ABC-12345 + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::Ident.new(nokogiri_frame) + + expected_result = { + ident: '37605030299', + ident_type: 'priv', + ident_country_code: 'EE' + } + + assert_equal instance.call, expected_result + end +end diff --git a/test/lib/deserializers/xml/legal_document_test.rb b/test/lib/deserializers/xml/legal_document_test.rb new file mode 100644 index 000000000..ac173ba4b --- /dev/null +++ b/test/lib/deserializers/xml/legal_document_test.rb @@ -0,0 +1,62 @@ +require 'test_helper' +require 'deserializers/xml/legal_document' + +class DeserializersXmlLegalDocumentTest < ActiveSupport::TestCase + def test_returns_nil_when_required_fields_not_present + xml_string = <<-XML + + + + + + john-001 + + + new name + + +123.4 + new-email@inbox.test + + + + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::LegalDocument.new(nokogiri_frame) + + assert_nil instance.call + end + + def test_returns_hash_when_document_exists + xml_string = <<-XML + + + + + + FIRST0:SH2027223711 + + wrong password + + + + + + 37605030299 + dGVzdCBmYWlsCg== + + + ABC-12345 + + + XML + + nokogiri_frame = Nokogiri::XML(xml_string).remove_namespaces! + instance = ::Deserializers::Xml::LegalDocument.new(nokogiri_frame) + expected_result = { body: "dGVzdCBmYWlsCg==", type: "pdf" } + + assert_equal expected_result, instance.call + end +end diff --git a/test/lib/serializers/registrant_api/domain_test.rb b/test/lib/serializers/registrant_api/domain_test.rb index 08648b29c..f2623741f 100644 --- a/test/lib/serializers/registrant_api/domain_test.rb +++ b/test/lib/serializers/registrant_api/domain_test.rb @@ -36,11 +36,17 @@ class SerializersRegistrantApiDomainTest < ActiveSupport::TestCase end def test_returns_contacts_name_and_uuid - assert_equal([{name: 'John', id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957'}, - {name: 'William', id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb'}].to_set, + assert_equal([{name: 'John', + id: 'eb2f2766-b44c-4e14-9f16-32ab1a7cb957', + email: 'john@inbox.test'}, + {name: 'William', + id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb', + email: 'william@inbox.test'}].to_set, @json[:admin_contacts].to_set) - assert_equal([{name: 'William', id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb'}].to_set, + assert_equal([{name: 'William', + id: '0aa54704-d6f7-4ca9-b8ca-2827d9a4e4eb', + email: 'william@inbox.test'}].to_set, @json[:tech_contacts].to_set) end @@ -70,7 +76,7 @@ class SerializersRegistrantApiDomainTest < ActiveSupport::TestCase def test_other_fields_are_also_present keys = %i[id name registrar registered_at valid_to created_at updated_at registrant tech_contacts admin_contacts transfer_code name_dirty name_puny period - period_unit creator_str updator_str legacy_id legacy_registrar_id legacy_registrant_id + period_unit creator_str updator_str outzone_at delete_date registrant_verification_asked_at registrant_verification_token pending_json force_delete_date statuses locked_by_registrant_at status_notes nameservers] diff --git a/test/mailers/domain_delete_mailer_test.rb b/test/mailers/domain_delete_mailer_test.rb index e6a39ff3d..ae060921f 100644 --- a/test/mailers/domain_delete_mailer_test.rb +++ b/test/mailers/domain_delete_mailer_test.rb @@ -73,9 +73,9 @@ class DomainDeleteMailerTest < ActionMailer::TestCase assert_emails 1 assert_equal ['legal@registry.test'], email.from - assert_equal %w[jane@mail.test john@inbox.test], email.to + assert_equal @domain.force_delete_contact_emails, email.to assert_equal 'Domeen shop.test on kustutusmenetluses' \ ' / Domain shop.test is in deletion process' \ ' / Домен shop.test в процессе удаления', email.subject end -end \ No newline at end of file +end diff --git a/test/models/api_user_test.rb b/test/models/api_user_test.rb index 20d655a9c..ecbff5cbb 100644 --- a/test/models/api_user_test.rb +++ b/test/models/api_user_test.rb @@ -63,6 +63,25 @@ class ApiUserTest < ActiveSupport::TestCase assert_nil ApiUser.find_by_id_card(id_card) end + def test_verifies_pki_status + certificate = certificates(:api) + + assert @user.pki_ok?(certificate.crt, certificate.common_name, api: true) + assert_not @user.pki_ok?(certificate.crt, 'invalid-cn', api: true) + + certificate = certificates(:registrar) + + assert @user.pki_ok?(certificate.crt, certificate.common_name, api: false) + assert_not @user.pki_ok?(certificate.crt, 'invalid-cn', api: false) + + certificate.update(revoked: true) + assert_not @user.pki_ok?(certificate.crt, certificate.common_name, api: false) + + certificate = certificates(:api) + certificate.update(revoked: true) + assert_not @user.pki_ok?(certificate.crt, certificate.common_name, api: true) + end + private def valid_user diff --git a/test/models/bank_transaction_test.rb b/test/models/bank_transaction_test.rb index 0e4d88bd6..b8b0f65f7 100644 --- a/test/models/bank_transaction_test.rb +++ b/test/models/bank_transaction_test.rb @@ -6,9 +6,93 @@ class BankTransactionTest < ActiveSupport::TestCase @invoice = invoices(:one) end - def test_matches_against_invoice_number_and_reference_number - create_payable_invoice(number: '2222', total: 10, reference_no: '1111') - transaction = BankTransaction.new(description: 'invoice #2222', sum: 10, reference_no: '1111') + def test_matches_against_invoice_nubmber_and_reference_number + create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') + transaction = BankTransaction.new(description: 'invoice #2222', sum: 10, reference_no: '1234567') + + assert_difference 'AccountActivity.count' do + transaction.autobind_invoice + end + end + + def test_binds_if_this_sum_invoice_already_present + create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') + another_invoice = @invoice.dup + another_invoice.save(validate: false) + another_invoice.update(reference_no: '7654321', number: '2221') + + another_item = @invoice.items.first.dup + another_item.invoice = another_invoice + another_item.save + another_invoice.reload + + first_transaction = BankTransaction.new(description: 'invoice #2221', + sum: 10, + description: 'Order nr 1 from registrar 1234567 second number 2345678') + + first_transaction.create_activity(another_invoice.buyer, another_invoice) + + transaction = BankTransaction.new(description: 'invoice #2222', + sum: 10, + description: 'Order nr 1 from registrar 1234567 second number 2345678') + + assert_difference 'AccountActivity.count' do + transaction.autobind_invoice + end + end + + def test_binds_if_this_sum_cancelled_invoice_already_present + create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') + another_invoice = @invoice.dup + another_invoice.save(validate: false) + + + another_item = @invoice.items.first.dup + another_item.invoice = another_invoice + + another_item.save + another_invoice.reload + another_invoice.update(reference_no: '1234567', number: '2221', cancelled_at: Time.zone.now) + + transaction = BankTransaction.new(description: 'invoice #2222', + sum: 10, + description: 'Order nr 1 from registrar 1234567 second number 2345678') + + assert_difference 'AccountActivity.count' do + transaction.autobind_invoice + end + end + + def test_marks_the_first_one_as_paid_if_same_sum + create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') + another_invoice = @invoice.dup + another_invoice.save(validate: false) + another_invoice.update(reference_no: '7654321', number: '2221') + + another_item = @invoice.items.first.dup + another_item.invoice = another_invoice + another_item.save + another_invoice.reload + + transaction = BankTransaction.new(description: 'invoice #2222', + sum: 10, + description: 'Order nr 1 from registrar 1234567 second number 2345678') + + assert_difference 'AccountActivity.count' do + transaction.autobind_invoice + end + + @invoice.reload + another_invoice.reload + assert(@invoice.paid?) + assert_not(another_invoice.paid?) + end + + def test_matches_against_invoice_nubmber_and_reference_number_in_description + create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') + transaction = BankTransaction.new(description: 'invoice #2222', + sum: 10, + description: 'Order nr 1 from registrar 1234567 second number 2345678') assert_difference 'AccountActivity.count' do transaction.autobind_invoice diff --git a/test/models/concerns/versions_test.rb b/test/models/concerns/versions_test.rb new file mode 100644 index 000000000..2a54b4476 --- /dev/null +++ b/test/models/concerns/versions_test.rb @@ -0,0 +1,28 @@ +require 'test_helper' + +class VersionsTest < ActiveSupport::TestCase + + def test_if_gets_all_versions_without_error_if_ignored_column_present + @nameserver = nameservers(:shop_ns1) + @nameserver.update(hostname: 'ns99.bestnames.test') + @ignored_column_title = Nameserver.ignored_columns.first + + version = NameserverVersion.last + hash = version.object + hash[@ignored_column_title] = 123456 + version.update(object: hash) + + assert_nothing_raised do + Nameserver.all_versions_for([@nameserver.id], Time.zone.now) + end + end + + def test_if_gets_all_versions_without_error_if_no_ignored_column + @account = accounts(:cash) + @account.update(currency: 'USD') + + assert_nothing_raised do + Account.all_versions_for([@account.id], Time.zone.now) + end + end +end diff --git a/test/models/contact/disclosable_test.rb b/test/models/contact/disclosable_test.rb index 4b944513d..02adfbb08 100644 --- a/test/models/contact/disclosable_test.rb +++ b/test/models/contact/disclosable_test.rb @@ -28,7 +28,7 @@ class ContactDisclosableTest < ActiveSupport::TestCase @contact.disclosed_attributes = %w[some undisclosable] assert @contact.invalid? - assert_includes @contact.errors.get(:disclosed_attributes), 'contain unsupported attribute(s)' + assert_includes @contact.errors[:disclosed_attributes], 'contain unsupported attribute(s)' end def test_valid_when_attribute_is_disclosable diff --git a/test/models/contact_test.rb b/test/models/contact_test.rb index 8a2301395..000333d57 100644 --- a/test/models/contact_test.rb +++ b/test/models/contact_test.rb @@ -3,6 +3,11 @@ require 'test_helper' class ContactTest < ActiveSupport::TestCase setup do @contact = contacts(:john) + @old_validation_type = Truemail.configure.default_validation_type + end + + teardown do + Truemail.configure.default_validation_type = @old_validation_type end def test_valid_contact_fixture_is_valid @@ -61,16 +66,39 @@ class ContactTest < ActiveSupport::TestCase assert contact.invalid? end - def test_validates_email_format + def test_email_verification_valid contact = valid_contact - - contact.email = 'invalid' - assert contact.invalid? - - contact.email = 'valid@registrar.test' + contact.email = 'info@internet.ee' assert contact.valid? end + def test_email_verification_smtp_error + Truemail.configure.default_validation_type = :smtp + + contact = valid_contact + contact.email = 'somecrude1337joke@internet.ee' + assert contact.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_smtp_check_error'), contact.errors.messages[:email].first + end + + def test_email_verification_mx_error + Truemail.configure.default_validation_type = :mx + + contact = valid_contact + contact.email = 'somecrude31337joke@somestrange31337domain.ee' + assert contact.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_mx_check_error'), contact.errors.messages[:email].first + end + + def test_email_verification_regex_error + Truemail.configure.default_validation_type = :regex + + contact = valid_contact + contact.email = 'some@strangesentence@internet.ee' + assert contact.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_regex_check_error'), contact.errors.messages[:email].first + end + def test_invalid_without_phone contact = valid_contact contact.phone = '' @@ -124,6 +152,8 @@ class ContactTest < ActiveSupport::TestCase end def test_address + Setting.address_processing = true + address = Contact::Address.new('new street', '83746', 'new city', 'new state', 'EE') @contact.address = address @contact.save! @@ -169,15 +199,15 @@ class ContactTest < ActiveSupport::TestCase end def test_linked_when_in_use_as_registrant - Domain.update_all(registrant_id: @contact) + Domain.update_all(registrant_id: @contact.id) DomainContact.delete_all assert @contact.linked? end def test_linked_when_in_use_as_domain_contact - Domain.update_all(registrant_id: contacts(:william)) - DomainContact.update_all(contact_id: @contact) + Domain.update_all(registrant_id: contacts(:william).id) + DomainContact.first.update(contact_id: @contact.id) assert @contact.linked? end @@ -210,6 +240,7 @@ class ContactTest < ActiveSupport::TestCase end def test_normalizes_country_code + Setting.address_processing = true contact = Contact.new(country_code: 'us') contact.validate assert_equal 'US', contact.country_code @@ -248,16 +279,35 @@ class ContactTest < ActiveSupport::TestCase assert_equal %w[ok], contact.statuses end + def test_whois_gets_updated_after_contact_save + @contact.name = 'SomeReallyWeirdRandomTestName' + domain = @contact.registrant_domains.first + + @contact.save! + + assert_equal domain.whois_record.try(:json).try(:[], 'registrant'), @contact.name + end + + def test_creates_email_verification_in_unicode + unicode_email = 'suur@äri.ee' + punycode_email = Contact.unicode_to_punycode(unicode_email) + + @contact.email = punycode_email + @contact.save + + assert_equal @contact.email_verification.email, unicode_email + end + private def make_contact_free_of_domains_where_it_acts_as_a_registrant(contact) other_contact = contacts(:william) assert_not_equal other_contact, contact - Domain.update_all(registrant_id: other_contact) + Domain.update_all(registrant_id: other_contact.id) end def unlinked_contact - Domain.update_all(registrant_id: contacts(:william)) + Domain.update_all(registrant_id: contacts(:william).id) DomainContact.delete_all contacts(:john) end diff --git a/test/models/deposit_test.rb b/test/models/deposit_test.rb index d8fc2d02a..171316f65 100644 --- a/test/models/deposit_test.rb +++ b/test/models/deposit_test.rb @@ -36,22 +36,22 @@ class DepositTest < ActiveSupport::TestCase def test_amount_is_converted_from_string @deposit.amount = "12.00" - assert_equal(BigDecimal.new("12.00"), @deposit.amount) + assert_equal(BigDecimal("12.00"), @deposit.amount) @deposit.amount = "12,11" - assert_equal(BigDecimal.new("12.11"), @deposit.amount) + assert_equal(BigDecimal("12.11"), @deposit.amount) end def test_amount_is_converted_from_float @deposit.amount = 12.0044 - assert_equal(BigDecimal.new("12.0044"), @deposit.amount) + assert_equal(BigDecimal("12.0044"), @deposit.amount) @deposit.amount = 12.0144 - assert_equal(BigDecimal.new("12.0144"), @deposit.amount) + assert_equal(BigDecimal("12.0144"), @deposit.amount) end def test_amount_is_converted_from_nil @deposit.amount = nil - assert_equal(BigDecimal.new("0.00"), @deposit.amount) + assert_equal(BigDecimal("0.00"), @deposit.amount) end end diff --git a/test/models/directo_test.rb b/test/models/directo_test.rb new file mode 100644 index 000000000..603a38d15 --- /dev/null +++ b/test/models/directo_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class DirectoTest < ActiveSupport::TestCase +end diff --git a/test/models/disputed_domain_test.rb b/test/models/disputed_domain_test.rb new file mode 100644 index 000000000..01897e19b --- /dev/null +++ b/test/models/disputed_domain_test.rb @@ -0,0 +1,52 @@ +require 'test_helper' + +class DisputedDomainTest < ActiveSupport::TestCase + setup do + @dispute = disputes(:active) + end + + def test_fixture_is_valid + assert @dispute.valid? + end + + def test_can_be_closed_by_domain_name + travel_to Time.zone.parse('2010-10-05') + + Dispute.close_by_domain(@dispute.domain_name) + @dispute.reload + + assert @dispute.closed + end + + def test_syncs_password_to_reserved + dispute = Dispute.new(domain_name: 'reserved.test', starts_at: Time.zone.today, password: 'disputepw') + dispute.save + dispute.reload + assert_equal dispute.password, ReservedDomain.find_by(name: dispute.domain_name).password + end + + def test_domain_name_zone_is_validated + dispute = Dispute.new(domain_name: 'correct.test', starts_at: Time.zone.today) + assert dispute.valid? + + dispute.domain_name = 'zone.is.unrecognized.test' + assert_not dispute.valid? + end + + def test_dispute_can_not_be_created_if_another_active_is_present + dispute = Dispute.new(domain_name: @dispute.domain_name, + starts_at: @dispute.starts_at + 1.day) + assert_not dispute.valid? + end + + def test_expires_at_date_is_appended_automatically + dispute = Dispute.new(domain_name: 'random.test', starts_at: Time.zone.today) + assert dispute.valid? + assert_equal dispute.expires_at, dispute.starts_at + 3.years + end + + def test_starts_at_must_be_present + dispute = Dispute.new(domain_name: 'random.test') + assert_not dispute.valid? + end +end diff --git a/test/models/dns/domain_name_test.rb b/test/models/dns/domain_name_test.rb index 5d0dd5386..4f8922d32 100644 --- a/test/models/dns/domain_name_test.rb +++ b/test/models/dns/domain_name_test.rb @@ -13,6 +13,8 @@ class AuctionDoubleTest < ActiveSupport::TestCase end class DNS::DomainNameTest < ActiveSupport::TestCase + fixtures 'whois/records' + def test_available_when_not_at_auction domain_name = DNS::DomainName.new('auction.test') auctions(:one).update!(domain: 'auction.test', status: Auction.statuses[:domain_registered]) @@ -131,7 +133,10 @@ class DNS::DomainNameTest < ActiveSupport::TestCase def test_blocked assert_equal 'blocked.test', blocked_domains(:one).name + assert_equal 'blockedäöüõ.test', blocked_domains(:idn).name assert DNS::DomainName.new('blocked.test').blocked? + assert DNS::DomainName.new('blockedäöüõ.test').blocked? + assert DNS::DomainName.new(SimpleIDN.to_ascii('blockedäöüõ.test')).blocked? assert_not DNS::DomainName.new('nonblocked .test').blocked? end diff --git a/test/models/dns/zone_test.rb b/test/models/dns/zone_test.rb index c18f9592a..fab4c6355 100644 --- a/test/models/dns/zone_test.rb +++ b/test/models/dns/zone_test.rb @@ -124,6 +124,60 @@ class DNS::ZoneTest < ActiveSupport::TestCase assert zone.invalid? end + def test_determines_if_subzone + zone = valid_zone + zone.update(origin: 'pri.ee') + assert zone.subzone? + end + + def test_updates_whois_after_update + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + whois_record = Whois::Record.find_by(name: subzone.origin) + assert whois_record.present? + end + + def test_has_setting_info_as_contacts_for_subzones + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + whois_record = Whois::Record.find_by(name: subzone.origin) + assert whois_record.present? + + assert_equal Setting.registry_whois_disclaimer, whois_record.json['disclaimer'] + assert_equal Setting.registry_email, whois_record.json['email'] + assert_equal Setting.registry_juridical_name, whois_record.json['registrar'] + assert_equal Setting.registry_url, whois_record.json['registrar_website'] + assert_equal Setting.registry_phone, whois_record.json['registrar_phone'] + + assert_equal Setting.registry_juridical_name, whois_record.json['registrant'] + assert_equal Setting.registry_reg_no, whois_record.json['registrant_reg_no'] + assert_equal Setting.registry_country_code, whois_record.json['registrant_ident_country_code'] + + contact = { name: Setting.registry_invoice_contact, email: Setting.registry_email, + disclosed_attributes: %w[name email] }.with_indifferent_access + + assert_equal contact, whois_record.json['admin_contacts'][0] + assert_equal contact, whois_record.json['tech_contacts'][0] + end + + def test_deletes_whois_record_after_destroy + subzone = dns_zones(:one).dup + + subzone.origin = 'sub.zone' + subzone.save + + assert Whois::Record.find_by(name: subzone.origin).present? + + subzone.destroy + assert_nil Whois::Record.find_by(name: subzone.origin) + end + private def valid_zone diff --git a/test/models/domain/domain_version_test.rb b/test/models/domain/domain_version_test.rb index 74844f3af..2139c21c1 100644 --- a/test/models/domain/domain_version_test.rb +++ b/test/models/domain/domain_version_test.rb @@ -16,7 +16,7 @@ class DomainVersionTest < ActiveSupport::TestCase def test_assigns_creator_to_paper_trail_whodunnit duplicate_domain = prepare_duplicate_domain - PaperTrail.whodunnit = @user.id_role_username + PaperTrail.request.whodunnit = @user.id_role_username assert_difference 'duplicate_domain.versions.count', 1 do duplicate_domain.save! end @@ -28,7 +28,7 @@ class DomainVersionTest < ActiveSupport::TestCase end def test_assigns_updator_to_paper_trail_whodunnit - PaperTrail.whodunnit = @user.id_role_username + PaperTrail.request.whodunnit = @user.id_role_username assert_difference '@domain.versions.count', 1 do @domain.apply_registry_lock diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index 9092fad86..e3818c484 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -1,37 +1,70 @@ require 'test_helper' -class DomainForceDeleteTest < ActiveSupport::TestCase +class NewDomainForceDeleteTest < ActiveSupport::TestCase setup do @domain = domains(:shop) - @original_redemption_grace_period = Setting.redemption_grace_period - end - - teardown do - Setting.redemption_grace_period = @original_redemption_grace_period - end - - def test_schedules_force_delete - assert_not @domain.force_delete_scheduled? Setting.redemption_grace_period = 30 + end + + def test_schedules_force_delete_fast_track + assert_not @domain.force_delete_scheduled? travel_to Time.zone.parse('2010-07-05') - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.reload assert @domain.force_delete_scheduled? - assert_equal Date.parse('2010-08-05'), @domain.force_delete_date + assert_equal Date.parse('2010-08-20'), @domain.force_delete_date.to_date + assert_equal Date.parse('2010-07-06'), @domain.force_delete_start.to_date end - def test_scheduling_force_delete_adds_corresponding_statuses + def test_schedules_force_delete_soft_year_ahead + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + + @domain.schedule_force_delete(type: :soft) + @domain.reload + + assert @domain.force_delete_scheduled? + assert_equal Date.parse('2010-09-20'), @domain.force_delete_date.to_date + assert_equal Date.parse('2010-08-06'), @domain.force_delete_start.to_date + end + + def test_schedules_force_delete_soft_less_than_year_ahead + @domain.update_columns(valid_to: Time.zone.parse('2010-08-05'), + force_delete_date: nil) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + + @domain.schedule_force_delete(type: :soft) + @domain.reload + + assert @domain.force_delete_scheduled? + assert_nil @domain.force_delete_date + assert_nil @domain.force_delete_start + end + + def test_scheduling_soft_force_delete_adds_corresponding_statuses statuses_to_be_added = [ DomainStatus::FORCE_DELETE, DomainStatus::SERVER_RENEW_PROHIBITED, DomainStatus::SERVER_TRANSFER_PROHIBITED, - DomainStatus::SERVER_UPDATE_PROHIBITED, - DomainStatus::PENDING_DELETE, ] - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :soft) + @domain.reload + assert (@domain.statuses & statuses_to_be_added) == statuses_to_be_added + end + + def test_scheduling_fast_track_force_delete_adds_corresponding_statuses + statuses_to_be_added = [ + DomainStatus::FORCE_DELETE, + DomainStatus::SERVER_RENEW_PROHIBITED, + DomainStatus::SERVER_TRANSFER_PROHIBITED, + ] + + @domain.schedule_force_delete(type: :fast_track) @domain.reload assert (@domain.statuses & statuses_to_be_added) == statuses_to_be_added end @@ -43,12 +76,13 @@ class DomainForceDeleteTest < ActiveSupport::TestCase ] @domain.statuses = statuses_to_be_removed + %w[other-status] - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.reload assert_empty @domain.statuses & statuses_to_be_removed end def test_scheduling_force_delete_stops_pending_actions + Setting.redemption_grace_period = 45 statuses_to_be_removed = [ DomainStatus::PENDING_UPDATE, DomainStatus::PENDING_TRANSFER, @@ -57,33 +91,35 @@ class DomainForceDeleteTest < ActiveSupport::TestCase ] @domain.statuses = statuses_to_be_removed + %w[other-status] - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.reload assert_empty @domain.statuses & statuses_to_be_removed, 'Pending actions should be stopped' end def test_scheduling_force_delete_preserves_current_statuses @domain.statuses = %w[test1 test2] - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.reload assert_equal %w[test1 test2], @domain.statuses_before_force_delete end def test_scheduling_force_delete_bypasses_validation @domain = domains(:invalid) - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) assert @domain.force_delete_scheduled? end def test_force_delete_cannot_be_scheduled_when_a_domain_is_discarded @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) assert_raises StandardError do - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) end end def test_cancels_force_delete - @domain.update_columns(statuses: [DomainStatus::FORCE_DELETE], force_delete_date: '2010-07-05') + @domain.update_columns(statuses: [DomainStatus::FORCE_DELETE], + force_delete_date: Time.zone.parse('2010-07-05'), + force_delete_start: Time.zone.parse('2010-07-05') - 45.days) assert @domain.force_delete_scheduled? @domain.cancel_force_delete @@ -91,11 +127,12 @@ class DomainForceDeleteTest < ActiveSupport::TestCase assert_not @domain.force_delete_scheduled? assert_nil @domain.force_delete_date + assert_nil @domain.force_delete_start end def test_cancelling_force_delete_bypasses_validation @domain = domains(:invalid) - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.cancel_force_delete assert_not @domain.force_delete_scheduled? end @@ -105,12 +142,9 @@ class DomainForceDeleteTest < ActiveSupport::TestCase DomainStatus::FORCE_DELETE, DomainStatus::SERVER_RENEW_PROHIBITED, DomainStatus::SERVER_TRANSFER_PROHIBITED, - DomainStatus::SERVER_UPDATE_PROHIBITED, - DomainStatus::PENDING_DELETE, - DomainStatus::SERVER_MANUAL_INZONE ] @domain.statuses = @domain.statuses + statuses - @domain.schedule_force_delete + @domain.schedule_force_delete(type: :fast_track) @domain.cancel_force_delete @domain.reload @@ -118,13 +152,94 @@ class DomainForceDeleteTest < ActiveSupport::TestCase assert_empty @domain.statuses & statuses end - def test_cancelling_force_delete_restores_statuses_that_a_domain_had_before_force_delete - @domain.statuses_before_force_delete = ['test1', DomainStatus::DELETE_CANDIDATE] - - @domain.cancel_force_delete + def test_hard_force_delete_should_have_outzone_and_purge_date_with_time + @domain.schedule_force_delete(type: :fast_track) @domain.reload - assert_equal ['test1', DomainStatus::DELETE_CANDIDATE], @domain.statuses - assert_nil @domain.statuses_before_force_delete + assert_equal(@domain.purge_date.to_date, @domain.force_delete_date) + assert_equal(@domain.outzone_date.to_date, @domain.force_delete_start.to_date + + Setting.expire_warning_period.days) + assert(@domain.purge_date.is_a?(ActiveSupport::TimeWithZone)) + assert(@domain.outzone_date.is_a?(ActiveSupport::TimeWithZone)) + end + + def test_soft_force_delete_year_ahead_should_have_outzone_and_purge_date_with_time + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + @domain.update(template_name: 'legal_person') + travel_to Time.zone.parse('2010-07-05') + + @domain.schedule_force_delete(type: :soft) + + travel_to Time.zone.parse('2010-08-21') + DomainCron.start_client_hold + @domain.reload + + 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) + assert(@domain.purge_date.is_a?(ActiveSupport::TimeWithZone)) + assert(@domain.outzone_date.is_a?(ActiveSupport::TimeWithZone)) + end + + def test_force_delete_soft_year_ahead_sets_client_hold + asserted_status = DomainStatus::CLIENT_HOLD + + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + @domain.update(template_name: 'legal_person') + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + @domain.schedule_force_delete(type: :soft) + + travel_to Time.zone.parse('2010-08-21') + DomainCron.start_client_hold + @domain.reload + assert_includes(@domain.statuses, asserted_status) + end + + def test_force_delete_soft_year_ahead_not_sets_client_hold_before_threshold + asserted_status = DomainStatus::CLIENT_HOLD + + @domain.update_columns(valid_to: Time.zone.parse('2010-08-05'), + force_delete_date: nil) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + @domain.schedule_force_delete(type: :soft) + + travel_to Time.zone.parse('2010-07-06') + DomainCron.start_client_hold + @domain.reload + + assert_not_includes(@domain.statuses, asserted_status) + end + + def test_force_delete_fast_track_sets_client_hold + asserted_status = DomainStatus::CLIENT_HOLD + @domain.update_columns(valid_to: Time.zone.parse('2010-10-05'), + force_delete_date: nil) + + travel_to Time.zone.parse('2010-07-05') + + @domain.schedule_force_delete(type: :fast_track) + travel_to Time.zone.parse('2010-07-25') + DomainCron.start_client_hold + @domain.reload + + assert_includes(@domain.statuses, asserted_status) + end + + def test_not_sets_hold_before_treshold + asserted_status = DomainStatus::CLIENT_HOLD + @domain.update_columns(valid_to: Time.zone.parse('2010-10-05'), + force_delete_date: nil) + @domain.update(template_name: 'legal_person') + + travel_to Time.zone.parse('2010-07-05') + + @domain.schedule_force_delete(type: :fast_track) + travel_to Time.zone.parse('2010-07-06') + DomainCron.start_client_hold + @domain.reload + + assert_not_includes(@domain.statuses, asserted_status) end end diff --git a/test/models/domain/releasable/auctionable_test.rb b/test/models/domain/releasable/auctionable_test.rb index c78a148bc..de3ac0ff6 100644 --- a/test/models/domain/releasable/auctionable_test.rb +++ b/test/models/domain/releasable/auctionable_test.rb @@ -2,7 +2,7 @@ require 'test_helper' class DomainReleasableAuctionableTest < ActiveSupport::TestCase # Needed for `test_updates_whois` test because of `after_commit :update_whois_record` in Domain - self.use_transactional_fixtures = false + self.use_transactional_tests = false setup do @domain = domains(:shop) diff --git a/test/models/domain_cron_test.rb b/test/models/domain_cron_test.rb index 742bf2eaf..5b3b0120e 100644 --- a/test/models/domain_cron_test.rb +++ b/test/models/domain_cron_test.rb @@ -23,4 +23,33 @@ class DomainCronTest < ActiveSupport::TestCase assert_emails 1 end -end \ No newline at end of file + + def test_client_hold + Setting.redemption_grace_period = 30 + + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + @domain.schedule_force_delete(type: :soft) + @domain.reload + @domain.update(template_name: 'legal_person') + travel_to Time.zone.parse('2010-08-06') + DomainCron.start_client_hold + + assert_emails 1 + end + + def test_does_not_sets_hold_if_already_set + Setting.redemption_grace_period = 30 + + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + travel_to Time.zone.parse('2010-07-05') + @domain.schedule_force_delete(type: :soft) + @domain.reload + @domain.update(template_name: 'legal_person', statuses: [DomainStatus::CLIENT_HOLD]) + travel_to Time.zone.parse('2010-08-06') + DomainCron.start_client_hold + + assert_emails 0 + end +end diff --git a/test/models/domain_test.rb b/test/models/domain_test.rb index 194a10d72..726def1b1 100644 --- a/test/models/domain_test.rb +++ b/test/models/domain_test.rb @@ -31,7 +31,7 @@ class DomainTest < ActiveSupport::TestCase def test_validates_name_format assert_equal dns_zones(:one).origin, 'test' domain = valid_domain - subdomain_min_length = 2 + subdomain_min_length = 1 subdomain_max_length = 63 domain.name = '!invalid' @@ -46,9 +46,6 @@ class DomainTest < ActiveSupport::TestCase domain.name = 'example-.test' assert domain.invalid? - domain.name = "#{'a' * subdomain_min_length.pred}.test" - assert domain.invalid? - domain.name = "#{'a' * subdomain_max_length.next}.test" assert domain.invalid? @@ -137,9 +134,9 @@ class DomainTest < ActiveSupport::TestCase contact = contacts(:john) domain.admin_contacts << contact - domain.admin_contacts << contact - - assert domain.invalid? + assert_raise ActiveRecord::RecordNotUnique do + domain.admin_contacts << contact + end end def test_invalid_when_the_same_tech_contact_is_linked_twice @@ -147,9 +144,9 @@ class DomainTest < ActiveSupport::TestCase contact = contacts(:john) domain.tech_contacts << contact - domain.tech_contacts << contact - - assert domain.invalid? + assert_raise ActiveRecord::RecordNotUnique do + domain.tech_contacts << contact + end end def test_validates_name_server_count_when_name_servers_are_required @@ -247,7 +244,7 @@ class DomainTest < ActiveSupport::TestCase domain3 = domains(:library) domain3.update!(outzone_at: Time.zone.parse('2010-07-05 08:00:01')) Domain.connection.disable_referential_integrity do - Domain.delete_all("id NOT IN (#{[domain1.id, domain2.id, domain3.id].join(',')})") + Domain.where("id NOT IN (#{[domain1.id, domain2.id, domain3.id].join(',')})").delete_all end assert_equal [domain1.id], Domain.outzone_candidates.ids @@ -262,7 +259,7 @@ class DomainTest < ActiveSupport::TestCase domain3 = domains(:library) domain3.update!(valid_to: Time.zone.parse('2010-07-05 08:00:01')) Domain.connection.disable_referential_integrity do - Domain.delete_all("id NOT IN (#{[domain1.id, domain2.id, domain3.id].join(',')})") + Domain.where("id NOT IN (#{[domain1.id, domain2.id, domain3.id].join(',')})").delete_all end assert_equal [domain1.id, domain2.id].sort, Domain.expired.ids.sort @@ -405,6 +402,22 @@ class DomainTest < ActiveSupport::TestCase assert_not domain.active? end + def test_registrant_change_removes_force_delete + @domain.update_columns(valid_to: Time.zone.parse('2010-10-05'), + force_delete_date: nil) + @domain.update(template_name: 'legal_person') + travel_to Time.zone.parse('2010-07-05') + @domain.schedule_force_delete(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 + + @domain.registrant = other_registrant + @domain.save! + + assert_not(@domain.force_delete_scheduled?) + end + private def valid_domain diff --git a/test/models/epp/response/result/code_test.rb b/test/models/epp/response/result/code_test.rb index 3c75303f1..f16013180 100644 --- a/test/models/epp/response/result/code_test.rb +++ b/test/models/epp/response/result/code_test.rb @@ -28,6 +28,7 @@ class EppResponseResultCodeTest < ActiveSupport::TestCase codes = { completed_successfully: 1000, completed_successfully_action_pending: 1001, + completed_without_address: 1100, completed_successfully_no_messages: 1300, completed_successfully_ack_to_dequeue: 1301, completed_successfully_ending_session: 1500, @@ -58,6 +59,7 @@ class EppResponseResultCodeTest < ActiveSupport::TestCase descriptions = { 1000 => 'Command completed successfully', 1001 => 'Command completed successfully; action pending', + 1100 => 'Command completed successfully; Postal address data discarded', 1300 => 'Command completed successfully; no messages', 1301 => 'Command completed successfully; ack to dequeue', 1500 => 'Command completed successfully; ending session', diff --git a/test/models/payment_orders/bank_link_test.rb b/test/models/payment_orders/bank_link_test.rb index f1069819c..30d91cb7c 100644 --- a/test/models/payment_orders/bank_link_test.rb +++ b/test/models/payment_orders/bank_link_test.rb @@ -8,7 +8,7 @@ class BankLinkTest < ActiveSupport::TestCase super @invoice = invoices(:one) - @invoice.update!(total: 12) + @invoice.update!(account_activity: nil, total: 12) travel_to '2018-04-01 00:30 +0300' create_new_bank_link @@ -36,11 +36,11 @@ class BankLinkTest < ActiveSupport::TestCase 'VK_MAC': 'CZZvcptkxfuOxRR88JmT4N+Lw6Hs4xiQfhBWzVYldAcRTQbcB/lPf9MbJzBE4e1/HuslQgkdCFt5g1xW2lJwrVDBQTtP6DAHfvxU3kkw7dbk0IcwhI4whUl68/QCwlXEQTAVDv1AFnGVxXZ40vbm/aLKafBYgrirB5SUe8+g9FE=', 'VK_ENCODING': 'UTF-8', 'VK_LANG': 'ENG' - }.with_indifferent_access + }.as_json - @completed_bank_link = PaymentOrders::BankLink.new( - 'seb', @invoice, { response: params } - ) + @completed_bank_link = PaymentOrder.new(type: 'PaymentOrders::Seb', + invoice: @invoice, + response: params) end def create_cancelled_bank_link @@ -55,16 +55,17 @@ class BankLinkTest < ActiveSupport::TestCase 'VK_MAC': 'PElE2mYXXN50q2UBvTuYU1rN0BmOQcbafPummDnWfNdm9qbaGQkGyOn0XaaFGlrdEcldXaHBbZKUS0HegIgjdDfl2NOk+wkLNNH0Iu38KzZaxHoW9ga7vqiyKHC8dcxkHiO9HsOnz77Sy/KpWCq6cz48bi3fcMgo+MUzBMauWoQ=', 'VK_ENCODING': 'UTF-8', 'VK_LANG': 'ENG' - }.with_indifferent_access + }.as_json - @cancelled_bank_link = PaymentOrders::BankLink.new( - 'seb', @invoice, { response: params } - ) + @cancelled_bank_link = PaymentOrder.new(type: 'PaymentOrders::Seb', + invoice: @invoice, + response: params) end def create_new_bank_link - params = { return_url: 'return.url', response_url: 'response.url' } - @new_bank_link = PaymentOrders::BankLink.new('seb', @invoice, params) + @new_bank_link = PaymentOrder.new(type: 'PaymentOrders::Seb', invoice: @invoice) + @new_bank_link.return_url = 'return.url' + @new_bank_link.response_url = 'response.url' end def test_response_is_not_valid_when_it_is_missing @@ -105,21 +106,14 @@ class BankLinkTest < ActiveSupport::TestCase refute(@cancelled_bank_link.settled_payment?) end - def test_complete_transaction_calls_methods_on_transaction - mock_transaction = MiniTest::Mock.new - mock_transaction.expect(:sum= , '12.00', ['12.00']) - mock_transaction.expect(:bank_reference= , '1', ['1']) - mock_transaction.expect(:buyer_bank_code= , 'testvpos', ['testvpos']) - mock_transaction.expect(:buyer_iban= , '1234', ['1234']) - mock_transaction.expect(:paid_at= , Date.parse('2018-04-01 00:30:00 +0300'), [Time.parse('2018-04-01T00:30:00+0300')]) - mock_transaction.expect(:buyer_name=, 'John Doe', ['John Doe']) - mock_transaction.expect(:save!, true) - mock_transaction.expect(:autobind_invoice, AccountActivity.new) + def test_successful_payment_creates_bank_transaction + @completed_bank_link.complete_transaction - BankTransaction.stub(:find_by, mock_transaction) do - @completed_bank_link.complete_transaction - end + transaction = BankTransaction.find_by( + sum: @completed_bank_link.response['VK_AMOUNT'], + buyer_name: @completed_bank_link.response['VK_SND_NAME'] + ) - mock_transaction.verify + assert transaction.present? end end diff --git a/test/models/payment_orders/every_pay_test.rb b/test/models/payment_orders/every_pay_test.rb index 202efc1b7..1e560f32a 100644 --- a/test/models/payment_orders/every_pay_test.rb +++ b/test/models/payment_orders/every_pay_test.rb @@ -4,36 +4,38 @@ class EveryPayTest < ActiveSupport::TestCase def setup super - @invoice = invoices(:one) + @invoice = invoices(:unpaid) @invoice.update!(total: 12) - params = { - response: - { - utf8: '✓', - _method: 'put', - authenticity_token: 'OnA69vbccQtMt3C9wxEWigs5Gpf/7z+NoxRCMkFPlTvaATs8+OgMKF1I4B2f+vuK37zCgpWZaWWtyuslRRSwkw==', - nonce: '392f2d7748bc8cb0d14f263ebb7b8932', - timestamp: '1524136727', - api_username: 'ca8d6336dd750ddb', - transaction_result: 'completed', - payment_reference: 'fd5d27b59a1eb597393cd5ff77386d6cab81ae05067e18d530b10f3802e30b56', - payment_state: 'settled', - amount: '12.00', - order_reference: 'e468a2d59a731ccc546f2165c3b1a6', - account_id: 'EUR3D1', - cc_type: 'master_card', - cc_last_four_digits: '0487', - cc_month: '10', - cc_year: '2018', - cc_holder_name: 'John Doe', - hmac_fields: 'account_id,amount,api_username,cc_holder_name,cc_last_four_digits,cc_month,cc_type,cc_year,hmac_fields,nonce,order_reference,payment_reference,payment_state,timestamp,transaction_result', - hmac: 'efac1c732835668cd86023a7abc140506c692f0d', - invoice_id: '1', - }, - } - @every_pay = PaymentOrders::EveryPay.new('every_pay', @invoice, params) - @other_pay = PaymentOrders::EveryPay.new('every_pay', @invoice, {}) + response = { + "utf8": '✓', + "_method": 'put', + "authenticity_token": 'OnA69vbccQtMt3C9wxEWigs5Gpf/7z+NoxRCMkFPlTvaATs8+OgMKF1I4B2f+vuK37zCgpWZaWWtyuslRRSwkw=="', + "nonce": '392f2d7748bc8cb0d14f263ebb7b8932', + "timestamp": '1524136727', + "api_username": 'ca8d6336dd750ddb', + "transaction_result": 'completed', + "payment_reference": 'fd5d27b59a1eb597393cd5ff77386d6cab81ae05067e18d530b10f3802e30b56', + "payment_state": 'settled', + "amount": '12.00', + "order_reference": 'e468a2d59a731ccc546f2165c3b1a6', + "account_id": 'EUR3D1', + "cc_type": 'master_card', + "cc_last_four_digits": '0487', + "cc_month": '10', + "cc_year": '2018', + "cc_holder_name": 'John Doe', + "hmac_fields": 'account_id,amount,api_username,cc_holder_name,cc_last_four_digits,cc_month,cc_type,cc_year,hmac_fields,nonce,order_reference,payment_reference,payment_state,timestamp,transaction_result', + "hmac": 'efac1c732835668cd86023a7abc140506c692f0d', + "invoice_id": '2' + }.as_json + + @successful_payment = PaymentOrder.new(type: 'PaymentOrders::EveryPay', + invoice: @invoice, + response: response) + + @failed_payment = @successful_payment.dup + @failed_payment.response['payment_state'] = 'cancelled' travel_to Time.zone.parse('2018-04-01 00:30:00 +0000') end @@ -47,37 +49,37 @@ class EveryPayTest < ActiveSupport::TestCase transaction_type: 'charge', hmac_fields: 'account_id,amount,api_username,callback_url,customer_url,hmac_fields,nonce,order_reference,timestamp,transaction_type' } - form_fields = @every_pay.form_fields + form_fields = @successful_payment.form_fields expected_fields.each do |k, v| assert_equal(v, form_fields[k]) end end def test_valid_response_from_intermediary? - assert(@every_pay.valid_response_from_intermediary?) - refute(@other_pay.valid_response_from_intermediary?) + assert(@successful_payment.valid_response_from_intermediary?) + + @failed_payment.response = { 'what': 'definitely not valid everypay response' } + refute(@failed_payment.valid_response_from_intermediary?) + end + + def test_valid_and_successful_payment_is_determined + assert(@successful_payment.payment_received?) + refute(@failed_payment.payment_received?) end def test_settled_payment? - assert(@every_pay.settled_payment?) - other_pay = PaymentOrders::EveryPay.new( - 'every_pay', @invoice, {response: {payment_state: 'CANCELLED'}} - ) - refute(other_pay.settled_payment?) + assert(@successful_payment.settled_payment?) + refute(@failed_payment.settled_payment?) end - def test_complete_transaction_calls_methods_on_transaction - mock_transaction = MiniTest::Mock.new - mock_transaction.expect(:sum= , '12.00', ['12.00']) - mock_transaction.expect(:paid_at= , Date.strptime('1524136727', '%s'), [Date.strptime('1524136727', '%s')]) - mock_transaction.expect(:buyer_name=, 'John Doe', ['John Doe']) - mock_transaction.expect(:save!, true) - mock_transaction.expect(:autobind_invoice, AccountActivity.new) + def test_successful_payment_creates_bank_transaction + @successful_payment.complete_transaction - BankTransaction.stub(:find_by, mock_transaction) do - @every_pay.complete_transaction - end + transaction = BankTransaction.find_by( + sum: @successful_payment.response['amount'], + buyer_name: @successful_payment.response['cc_holder_name'] + ) - mock_transaction.verify + assert transaction.present? end end diff --git a/test/models/payment_orders_test.rb b/test/models/payment_orders_test.rb index 252ba0582..43996c6bc 100644 --- a/test/models/payment_orders_test.rb +++ b/test/models/payment_orders_test.rb @@ -5,23 +5,21 @@ class PaymentOrdersTest < ActiveSupport::TestCase super @original_methods = ENV['payment_methods'] - @original_seb_URL = ENV['seb_payment_url'] - ENV['payment_methods'] = 'seb, swed, credit_card' + @original_seb_url = ENV['seb_payment_url'] + ENV['payment_methods'] = 'seb, swed, every_pay' ENV['seb_payment_url'] = nil - @not_implemented_payment = PaymentOrders::Base.new( - 'not_implemented', Invoice.new - ) + @not_implemented_payment = PaymentOrder.new(invoice: Invoice.new) end def teardown super ENV['payment_methods'] = @original_methods - ENV['seb_payment_url'] = @original_seb_URL + ENV['seb_payment_url'] = @original_seb_url end def test_variable_assignment - assert_equal 'not_implemented', @not_implemented_payment.type + assert_nil @not_implemented_payment.type assert_nil @not_implemented_payment.response_url assert_nil @not_implemented_payment.return_url assert_nil @not_implemented_payment.form_url @@ -45,14 +43,61 @@ class PaymentOrdersTest < ActiveSupport::TestCase end end - def test_that_create_with_type_raises_argument_error - assert_raise ArgumentError do - PaymentOrders.create_with_type("not_implemented", Invoice.new) + def test_correct_channel_is_assigned + everypay_channel = PaymentOrder.new_with_type(type: 'every_pay', invoice: @invoice) + assert_equal everypay_channel.channel, 'EveryPay' + assert_equal everypay_channel.class.config_namespace_name, 'every_pay' + + swed_channel = PaymentOrder.new_with_type(type: 'swed', invoice: @invoice) + assert_equal swed_channel.channel, 'Swed' + assert_equal swed_channel.class.config_namespace_name, 'swed' + + seb_channel = PaymentOrder.new_with_type(type: 'seb', invoice: @invoice) + assert_equal seb_channel.channel, 'Seb' + assert_equal seb_channel.class.config_namespace_name, 'seb' + + lhv_channel = PaymentOrder.new_with_type(type: 'lhv', invoice: @invoice) + assert_equal lhv_channel.channel, 'Lhv' + assert_equal lhv_channel.class.config_namespace_name, 'lhv' + + admin_channel = PaymentOrder.new_with_type(type: 'admin_payment', invoice: @invoice) + assert_equal admin_channel.channel, 'AdminPayment' + assert_equal admin_channel.class.config_namespace_name, 'admin_payment' + + system_channel = PaymentOrder.new_with_type(type: 'system_payment', invoice: @invoice) + assert_equal system_channel.channel, 'SystemPayment' + assert_equal system_channel.class.config_namespace_name, 'system_payment' + end + + def test_can_not_create_order_for_paid_invoice + invoice = invoices(:one) + payment_order = PaymentOrder.new_with_type(type: 'every_pay', invoice: invoice) + assert payment_order.invalid? + assert_includes payment_order.errors[:invoice], 'is already paid' + end + + def test_order_without_channel_is_invalid + payment_order = PaymentOrder.new + assert payment_order.invalid? + assert_includes payment_order.errors[:type], 'is not supported' + end + + def test_can_not_create_order_with_invalid_type + assert_raise NameError do + PaymentOrder.new_with_type(type: 'not_implemented', invoice: Invoice.new) end end - def test_create_with_correct_subclass - payment = PaymentOrders.create_with_type('seb', Invoice.new) - assert_equal PaymentOrders::BankLink, payment.class + def test_supported_method_bool_does_not_fail + assert_not PaymentOrder.supported_method?('not_implemented', shortname: true) + assert PaymentOrder.supported_method?('every_pay', shortname: true) + + assert_not PaymentOrder.supported_method?('PaymentOrders::NonExistant') + assert PaymentOrder.supported_method?('PaymentOrders::EveryPay') + end + + def test_can_create_with_correct_subclass + payment = PaymentOrder.new_with_type(type: 'seb', invoice: Invoice.new) + assert_equal PaymentOrders::Seb, payment.class end end diff --git a/test/models/registrant_verification_test.rb b/test/models/registrant_verification_test.rb new file mode 100644 index 000000000..ef4038784 --- /dev/null +++ b/test/models/registrant_verification_test.rb @@ -0,0 +1,33 @@ +require 'test_helper' + +class RegistrantVerificationTest < ActiveSupport::TestCase + + setup do + @domain = domains(:shop) + @initiator = users(:api_bestnames).username + @token = 'zzzzz' + @domain.update(statuses: [DomainStatus::PENDING_UPDATE], + registrant_verification_asked_at: Time.zone.now - 1.day, + registrant_verification_token: @token) + end + + def test_audit_log + registrant_verification = registrant_verifications(:one) + random_action = "random#{rand(100)}" + + assert_difference -> { RegistrantVerificationVersion.count } do + registrant_verification.update_attributes!(action: random_action) + end + end + + def test_reject_changes + @registrant_verification = RegistrantVerification.new(domain_id: @domain.id, + verification_token: @token) + start_versions_count = RegistrantVerificationVersion.count + + assert_nothing_raised do + @registrant_verification.domain_registrant_change_reject!("email link, #{@initiator}") + end + assert_equal RegistrantVerificationVersion.count, start_versions_count + 1 + end +end diff --git a/test/models/registrar_test.rb b/test/models/registrar_test.rb index eaed654ec..091b8e6f4 100644 --- a/test/models/registrar_test.rb +++ b/test/models/registrar_test.rb @@ -5,11 +5,13 @@ class RegistrarTest < ActiveSupport::TestCase @registrar = registrars(:bestnames) @original_default_language = Setting.default_language @original_days_to_keep_invoices_active = Setting.days_to_keep_invoices_active + @old_validation_type = Truemail.configure.default_validation_type end teardown do Setting.default_language = @original_default_language Setting.days_to_keep_invoices_active = @original_days_to_keep_invoices_active + Truemail.configure.default_validation_type = @old_validation_type end def test_valid_registrar_is_valid @@ -38,16 +40,99 @@ class RegistrarTest < ActiveSupport::TestCase assert registrar.invalid? end - def test_email_format_validation + def test_email_verification_valid registrar = valid_registrar + registrar.email = 'info@internet.ee' + registrar.billing_email = nil - registrar.email = 'invalid' - assert registrar.invalid? - - registrar.email = 'valid@email.test' assert registrar.valid? end + def test_email_verification_smtp_error + Truemail.configure.default_validation_type = :smtp + + registrar = valid_registrar + registrar.email = 'somecrude1337joke@internet.ee' + registrar.billing_email = nil + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_smtp_check_error'), registrar.errors.messages[:email].first + end + + def test_email_verification_mx_error + Truemail.configure.default_validation_type = :mx + + registrar = valid_registrar + registrar.email = 'somecrude31337joke@somestrange31337domain.ee' + registrar.billing_email = nil + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_mx_check_error'), registrar.errors.messages[:email].first + end + + def test_email_verification_regex_error + Truemail.configure.default_validation_type = :regex + + registrar = valid_registrar + registrar.email = 'some@strangesentence@internet.ee' + registrar.billing_email = nil + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_regex_check_error'), registrar.errors.messages[:email].first + end + + def test_billing_email_verification_valid + registrar = valid_registrar + registrar.billing_email = 'info@internet.ee' + + assert registrar.valid? + end + + def test_billing_email_verification_smtp_error + Truemail.configure.default_validation_type = :smtp + + registrar = valid_registrar + registrar.billing_email = 'somecrude1337joke@internet.ee' + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_smtp_check_error'), registrar.errors.messages[:billing_email].first + end + + def test_billing_email_verification_mx_error + Truemail.configure.default_validation_type = :mx + + registrar = valid_registrar + registrar.billing_email = 'somecrude31337joke@somestrange31337domain.ee' + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_mx_check_error'), registrar.errors.messages[:billing_email].first + end + + def test_billing_email_verification_regex_error + Truemail.configure.default_validation_type = :regex + + registrar = valid_registrar + registrar.billing_email = 'some@strangesentence@internet.ee' + + assert registrar.invalid? + assert_equal I18n.t('activerecord.errors.models.contact.attributes.email.email_regex_check_error'), registrar.errors.messages[:billing_email].first + end + + def test_creates_email_verification_in_unicode + unicode_email = 'suur@äri.ee' + punycode_email = Registrar.unicode_to_punycode(unicode_email) + unicode_billing_email = 'billing@äri.ee' + punycode_billing_email = Registrar.unicode_to_punycode(unicode_billing_email) + + registrar = valid_registrar + registrar.email = punycode_email + registrar.billing_email = punycode_billing_email + registrar.save + + assert_equal registrar.email_verification.email, unicode_email + assert_equal registrar.billing_email_verification.email, unicode_billing_email + end + def test_invalid_without_accounting_customer_code registrar = valid_registrar registrar.accounting_customer_code = '' @@ -60,16 +145,6 @@ class RegistrarTest < ActiveSupport::TestCase assert registrar.valid? end - def test_billing_email_format_validation - registrar = valid_registrar - - registrar.billing_email = 'invalid' - assert registrar.invalid? - - registrar.billing_email = 'valid@email.test' - assert registrar.valid? - end - def test_returns_billing_email_when_provided billing_email = 'billing@registrar.test' registrar = Registrar.new(billing_email: billing_email) @@ -238,6 +313,33 @@ class RegistrarTest < ActiveSupport::TestCase assert_equal iban, registrar.e_invoice_iban end + def test_legal_doc_is_mandatory + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = true + assert @registrar.legaldoc_mandatory? + + Setting.legal_document_is_mandatory = old_value + end + + def test_legal_doc_is_not_mandatory_if_opted_out + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = true + @registrar.legaldoc_optout = true + @registrar.save(validate: false) + @registrar.reload + assert_not @registrar.legaldoc_mandatory? + + Setting.legal_document_is_mandatory = old_value + end + + def test_legal_doc_is_not_mandatory_globally + old_value = Setting.legal_document_is_mandatory + Setting.legal_document_is_mandatory = false + assert_not @registrar.legaldoc_mandatory? + + Setting.legal_document_is_mandatory = old_value + end + private def valid_registrar @@ -257,4 +359,4 @@ class RegistrarTest < ActiveSupport::TestCase Registry.current.vat_country = Country.new(:us) registrar end -end \ No newline at end of file +end diff --git a/test/models/whois/record_test.rb b/test/models/whois/record_test.rb index 5f2454105..3e727d80a 100644 --- a/test/models/whois/record_test.rb +++ b/test/models/whois/record_test.rb @@ -40,24 +40,36 @@ class Whois::RecordTest < ActiveSupport::TestCase end def test_updates_whois_record_from_auction_when_awaiting_payment - @auction.update!(domain: 'domain.test', status: Auction.statuses[:awaiting_payment]) + @auction.update!(domain: 'domain.test', + status: Auction.statuses[:awaiting_payment], + registration_deadline: registration_deadline) @whois_record.update!(name: 'domain.test') @whois_record.update_from_auction(@auction) @whois_record.reload assert_equal ({ 'name' => 'domain.test', 'status' => ['PendingRegistration'], - 'disclaimer' => 'disclaimer' }), @whois_record.json + 'disclaimer' => 'disclaimer', + 'registration_deadline' => registration_deadline.try(:to_s, :iso8601) }), + @whois_record.json end def test_updates_whois_record_from_auction_when_payment_received - @auction.update!(domain: 'domain.test', status: Auction.statuses[:payment_received]) + @auction.update!(domain: 'domain.test', + status: Auction.statuses[:payment_received], + registration_deadline: registration_deadline) @whois_record.update!(name: 'domain.test') @whois_record.update_from_auction(@auction) @whois_record.reload assert_equal ({ 'name' => 'domain.test', 'status' => ['PendingRegistration'], - 'disclaimer' => 'disclaimer' }), @whois_record.json + 'disclaimer' => 'disclaimer', + 'registration_deadline' => registration_deadline.try(:to_s, :iso8601) }), + @whois_record.json end -end \ No newline at end of file + + def registration_deadline + Time.zone.now + 10.days + end +end diff --git a/test/support/rails5_assertions.rb b/test/support/rails5_assertions.rb deleted file mode 100644 index 55a2e8dc6..000000000 --- a/test/support/rails5_assertions.rb +++ /dev/null @@ -1,94 +0,0 @@ -module ActiveSupport - module Testing - module Assertions - UNTRACKED = Object.new # :nodoc: - - # Assertion that the result of evaluating an expression is changed before - # and after invoking the passed in block. - # - # assert_changes 'Status.all_good?' do - # post :create, params: { status: { ok: false } } - # end - # - # You can pass the block as a string to be evaluated in the context of - # the block. A lambda can be passed for the block as well. - # - # assert_changes -> { Status.all_good? } do - # post :create, params: { status: { ok: false } } - # end - # - # The assertion is useful to test side effects. The passed block can be - # anything that can be converted to string with #to_s. - # - # assert_changes :@object do - # @object = 42 - # end - # - # The keyword arguments :from and :to can be given to specify the - # expected initial value and the expected value after the block was - # executed. - # - # assert_changes :@object, from: nil, to: :foo do - # @object = :foo - # end - # - # An error message can be specified. - # - # assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do - # post :create, params: { status: { incident: true } } - # end - def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block) - exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } - - before = exp.call - retval = yield - - unless from == UNTRACKED - error = "#{expression.inspect} isn't #{from.inspect}" - error = "#{message}.\n#{error}" if message - assert from === before, error - end - - after = exp.call - - if to == UNTRACKED - error = "#{expression.inspect} didn't changed" - error = "#{message}.\n#{error}" if message - assert_not_equal before, after, error - else - error = "#{expression.inspect} didn't change to #{to}" - error = "#{message}.\n#{error}" if message - assert to === after, error - end - - retval - end - - # Assertion that the result of evaluating an expression is changed before - # and after invoking the passed in block. - # - # assert_no_changes 'Status.all_good?' do - # post :create, params: { status: { ok: true } } - # end - # - # An error message can be specified. - # - # assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do - # post :create, params: { status: { ok: false } } - # end - def assert_no_changes(expression, message = nil, &block) - exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) } - - before = exp.call - retval = yield - after = exp.call - - error = "#{expression.inspect} did change to #{after}" - error = "#{message}.\n#{error}" if message - assert_equal before, after, error - - retval - end - end - end -end diff --git a/test/system/admin_area/api_users/new_test.rb b/test/system/admin_area/api_users/new_test.rb deleted file mode 100644 index d34b990c2..000000000 --- a/test/system/admin_area/api_users/new_test.rb +++ /dev/null @@ -1,25 +0,0 @@ -require 'application_system_test_case' - -class AdminAreaNewApiUserTest < ApplicationSystemTestCase - setup do - sign_in users(:admin) - end - - def test_new_api_user_creation_with_required_params - visit admin_api_users_url - click_link_or_button 'New API user' - - fill_in 'Username', with: 'newtest' - fill_in 'Password', with: 'testtest' - find('#api_user_registrar_id', visible: false).set(registrars(:bestnames).id) - - assert_difference 'ApiUser.count' do - click_link_or_button 'Save' - end - - assert_current_path admin_api_user_path(ApiUser.last) - assert_text 'Record created' - assert_text 'Username newtest' - assert_text 'Password testtest' - end -end \ No newline at end of file diff --git a/test/system/admin_area/api_users_test.rb b/test/system/admin_area/api_users_test.rb new file mode 100644 index 000000000..d79434ef6 --- /dev/null +++ b/test/system/admin_area/api_users_test.rb @@ -0,0 +1,14 @@ +require 'application_system_test_case' + +class AdminApiUsersSystemTest < ApplicationSystemTestCase + setup do + sign_in users(:admin) + end + + def test_shows_api_user_list + visit admin_api_users_path + + api_user = users(:api_bestnames) + assert_link api_user.username, href: admin_registrar_api_user_path(api_user.registrar, api_user) + end +end diff --git a/test/system/admin_area/bank_statement_test.rb b/test/system/admin_area/bank_statement_test.rb new file mode 100644 index 000000000..53cbcc177 --- /dev/null +++ b/test/system/admin_area/bank_statement_test.rb @@ -0,0 +1,16 @@ +require 'application_system_test_case' + +class AdminAreaBankStatementTest < ApplicationSystemTestCase + setup do + sign_in users(:admin) + travel_to Time.zone.parse('2010-07-05 00:30:00') + end + + def test_import_statement + assert_difference 'BankStatement.count', 1 do + visit import_admin_bank_statements_path + attach_file 'Th6 file', Rails.root.join('test', 'fixtures', 'files', 'bank_statement_test.txt').to_s + click_link_or_button 'Save' + end + end +end diff --git a/test/system/admin_area/contact_versions_test.rb b/test/system/admin_area/contact_versions_test.rb index 88d625c41..2559a203f 100644 --- a/test/system/admin_area/contact_versions_test.rb +++ b/test/system/admin_area/contact_versions_test.rb @@ -18,8 +18,8 @@ class ContactVersionsTest < ApplicationSystemTestCase def create_contact_with_history sql = <<-SQL.squish - INSERT INTO contacts (id, code, email, auth_info, registrar_id) - VALUES (75, 'test_code', 'test@inbox.test', '8b4d462aa04194ca78840a', #{@registrar.id}); + INSERT INTO contacts (id, name, code, email, auth_info, registrar_id) + VALUES (75, 'test_name', 'test_code', 'test@inbox.test', '8b4d462aa04194ca78840a', #{@registrar.id}); INSERT INTO log_contacts (item_type, item_id, event, whodunnit, object, object_changes, created_at, session, children, ident_updated_at, uuid) @@ -55,4 +55,4 @@ class ContactVersionsTest < ApplicationSystemTestCase assert_text 'Best Names' assert_text '23.04.18, 18:50 update 1-AdminUser' end -end \ No newline at end of file +end diff --git a/test/system/admin_area/domain_versions_test.rb b/test/system/admin_area/domain_versions_test.rb index 73db8d707..8ff90a562 100644 --- a/test/system/admin_area/domain_versions_test.rb +++ b/test/system/admin_area/domain_versions_test.rb @@ -18,8 +18,8 @@ class DomainVersionsTest < ApplicationSystemTestCase def create_domain_with_history sql = <<-SQL.squish - INSERT INTO contacts (id, code, email, auth_info, registrar_id) - VALUES (54, 'test_code', 'test@inbox.test', '8b4d462aa04194ca78840a', #{@registrar.id}); + INSERT INTO contacts (id, name, code, email, auth_info, registrar_id) + VALUES (54, 'test_code', 'test_name', 'test@inbox.test', '8b4d462aa04194ca78840a', #{@registrar.id}); INSERT INTO domains (id, name, name_puny, name_dirty, registrar_id, valid_to, registrant_id, transfer_code) @@ -59,4 +59,4 @@ class DomainVersionsTest < ApplicationSystemTestCase assert_text 'Best Names' assert_text '23.04.18, 18:50 update 1-AdminUser' end -end \ No newline at end of file +end diff --git a/test/system/admin_area/domains/force_delete_test.rb b/test/system/admin_area/domains/force_delete_test.rb index 5e135bf24..4ccc10923 100644 --- a/test/system/admin_area/domains/force_delete_test.rb +++ b/test/system/admin_area/domains/force_delete_test.rb @@ -28,9 +28,18 @@ class AdminAreaDomainForceDeleteTest < ApplicationSystemTestCase end end - def test_notifies_registrant_and_admin_contacts_by_email_by_default + def test_notifies_registrant_and_admin_contacts_by_email_if_fast_delete assert_emails 1 do visit edit_admin_domain_url(@domain) + find(:css, '#soft_delete').set(false) + click_link_or_button 'Force delete domain' + end + end + + def test_notifies_registrant_and_admin_contacts_by_email_if_soft_delete + assert_emails 0 do + visit edit_admin_domain_url(@domain) + find(:css, '#soft_delete').set(true) click_link_or_button 'Force delete domain' end end @@ -62,4 +71,4 @@ class AdminAreaDomainForceDeleteTest < ApplicationSystemTestCase assert_no_button 'Schedule force delete' assert_no_link 'Schedule force delete' end -end \ No newline at end of file +end diff --git a/test/system/admin_area/domains/legal_doc_test.rb b/test/system/admin_area/domains/legal_doc_test.rb new file mode 100644 index 000000000..00cc7cc3a --- /dev/null +++ b/test/system/admin_area/domains/legal_doc_test.rb @@ -0,0 +1,21 @@ +require 'application_system_test_case' + +class AdminAreaDomainsLegalDocTest < ApplicationSystemTestCase + setup do + sign_in users(:admin) + @domain = domains(:shop) + @document = LegalDocument.create( + document_type: 'pdf', + documentable_id: @domain.id, + documentable_type: 'Domain', + path: '\zzz\zzz' + ) + end + + def test_absent_doc_downloading_without_errors + visit admin_domain_url(@domain) + assert_nothing_raised do + click_on "#{@document.created_at}" + end + end +end diff --git a/test/system/admin_area/domains_test.rb b/test/system/admin_area/domains_test.rb index abd1d93fb..05e7d60f3 100644 --- a/test/system/admin_area/domains_test.rb +++ b/test/system/admin_area/domains_test.rb @@ -35,4 +35,15 @@ class AdminDomainsTestTest < ApplicationSystemTestCase assert_text 'deleteCandidate status has been removed' assert_no_link 'Remove deleteCandidate status' end + + def test_remove_domain_status + @domain.update!(statuses: [DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED]) + + visit edit_admin_domain_url(@domain) + + click_link_or_button 'Delete' + click_link_or_button 'Save' + + assert_text 'Domain updated!' + end end diff --git a/test/system/admin_area/registrars/api_users_test.rb b/test/system/admin_area/registrars/api_users_test.rb new file mode 100644 index 000000000..5d833dde2 --- /dev/null +++ b/test/system/admin_area/registrars/api_users_test.rb @@ -0,0 +1,75 @@ +require 'application_system_test_case' + +class AdminRegistrarsApiUsersSystemTest < ApplicationSystemTestCase + setup do + sign_in users(:admin) + end + + def test_creates_new_api_user_with_required_attributes + username = 'john' + registrar = registrars(:bestnames) + + visit admin_registrar_path(registrar) + click_on 'New API user' + + fill_in 'Username', with: username + fill_in 'Password', with: valid_password + click_on 'Create API user' + + assert_text 'API user has been successfully created' + assert_text "Username #{username}" + new_api_user = ApiUser.last + assert_current_path admin_registrar_api_user_path(registrar, new_api_user) + end + + def test_shows_api_user_details + api_user = users(:api_bestnames) + + visit admin_registrar_path(api_user.registrar) + click_on api_user.username + + assert_text "Username #{api_user.username}" + assert_text "Password #{api_user.plain_text_password}" + assert_link api_user.registrar.name, href: admin_registrar_path(api_user.registrar) + assert_text "Role #{api_user.roles.first}" + assert_text "Active #{api_user.active}" + end + + def test_updates_api_user + api_user = users(:api_bestnames) + new_username = 'new username' + assert_not_equal new_username, api_user.username + + visit admin_registrar_api_user_path(api_user.registrar, api_user) + click_link_or_button 'Edit' + fill_in 'Username', with: new_username + click_link_or_button 'Update API user' + + assert_text 'API user has been successfully updated' + assert_text "Username #{new_username}" + assert_current_path admin_registrar_api_user_path(api_user.registrar, api_user) + end + + def test_deletes_api_user + api_user = unassociated_api_user + + visit admin_registrar_api_user_path(api_user.registrar, api_user) + click_on 'Delete' + + assert_text 'API user has been successfully deleted' + assert_current_path admin_registrar_path(api_user.registrar) + end + + private + + def unassociated_api_user + new_api_user = users(:api_bestnames).dup + new_api_user.username = "unique-#{rand(100)}" + new_api_user.save! + new_api_user + end + + def valid_password + 'testtest' + end +end diff --git a/test/system/registrant_area/contacts/details_test.rb b/test/system/registrant_area/contacts/details_test.rb index 8152939a5..bf96046a6 100644 --- a/test/system/registrant_area/contacts/details_test.rb +++ b/test/system/registrant_area/contacts/details_test.rb @@ -24,18 +24,10 @@ class RegistrantAreaContactDetailsTest < ApplicationSystemTestCase end def test_registrant_user_cannot_access_contact_when_given_domain_belongs_to_another_user - suppress(ActionView::Template::Error) do + suppress(ActiveRecord::RecordNotFound) do visit registrant_domain_contact_url(domains(:metro), @contact) assert_response :not_found assert_no_text 'Name John' end end - - def test_unmanaged_contact_cannot_be_accessed - @contact.update!(ident: '12345') - - assert_raises ActiveRecord::RecordNotFound do - visit registrant_domain_contact_url(@domain, @contact) - end - end -end \ No newline at end of file +end diff --git a/test/system/registrant_area/contacts/update_test.rb b/test/system/registrant_area/contacts/update_test.rb index a7cee049e..07115579b 100644 --- a/test/system/registrant_area/contacts/update_test.rb +++ b/test/system/registrant_area/contacts/update_test.rb @@ -31,7 +31,7 @@ class RegistrantAreaContactUpdateTest < ApplicationIntegrationTest stub_auth_request request_body = { name: 'new name', email: 'new@inbox.test', phone: '+666.6' }.to_json - headers = { 'Content-Type' => Mime::JSON, + headers = { 'Content-Type' => Mime[:json], 'Authorization' => 'Bearer test-access-token' } url = "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}" update_request_stub = stub_request(:patch, url).with(body: request_body, headers: headers) @@ -115,7 +115,7 @@ class RegistrantAreaContactUpdateTest < ApplicationIntegrationTest country_code: 'AT', state: 'new state', } }.to_json - headers = { 'Content-type' => 'application/json', + headers = { 'Content-type' => Mime[:json], 'Authorization' => 'Bearer test-access-token' } url = "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}" update_request_stub = stub_request(:patch, url).with(body: request_body, headers: headers) @@ -141,14 +141,6 @@ class RegistrantAreaContactUpdateTest < ApplicationIntegrationTest assert_no_field 'Street' end - def test_unmanaged_contact_cannot_be_updated - @contact.update!(ident: '12345') - - assert_raises ActiveRecord::RecordNotFound do - visit registrant_domain_contact_url(@domain, @contact) - end - end - def test_fail_gracefully stub_auth_request @@ -174,7 +166,7 @@ class RegistrantAreaContactUpdateTest < ApplicationIntegrationTest body = { ident: '1234', first_name: 'Registrant', last_name: 'User' } stub_request(:post, 'https://api.test/api/v1/registrant/auth/eid').with(body: body) .to_return(body: { access_token: 'test-access-token' }.to_json, - headers: { 'Content-type' => 'application/json' }, + headers: { 'Content-type' => Mime[:json] }, status: 200) end end diff --git a/test/system/registrant_area/domains/domain_delete_confirms_test.rb b/test/system/registrant_area/domains/domain_delete_confirms_test.rb new file mode 100644 index 000000000..0eb61ada8 --- /dev/null +++ b/test/system/registrant_area/domains/domain_delete_confirms_test.rb @@ -0,0 +1,41 @@ +require 'application_system_test_case' + +class DomainDeleteConfirmsTest < ApplicationSystemTestCase + setup do + @user = users(:registrant) + sign_in @user + + @domain = domains(:shop) + @domain.registrant_verification_asked!('\n', @user.id) + @domain.pending_delete! + end + + 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' + assert_text 'Domain registrant change has successfully received.' + + @domain.reload + assert_includes @domain.statuses, 'serverHold' + end + + 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' + assert_text 'Domain registrant change has been rejected successfully.' + + @domain.reload + assert_equal ['ok'], @domain.statuses + end + + def test_saves_whodunnit_info_after_verifivation + visit registrant_domain_delete_confirm_url(@domain.id, token: @domain.registrant_verification_token) + token = @domain.registrant_verification_token + click_on 'Confirm domain delete' + assert_text 'Domain registrant change has successfully received.' + + refute RegistrantVerification.find_by(verification_token:token).updator_str.empty? + 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 944a1f91f..69b755499 100644 --- a/test/system/registrar_area/bulk_change/bulk_transfer_test.rb +++ b/test/system/registrar_area/bulk_change/bulk_transfer_test.rb @@ -7,7 +7,7 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase def test_transfer_multiple_domains_in_bulk request_body = { data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } } - headers = { 'Content-type' => 'application/json' } + headers = { 'Content-type' => Mime[:json] } request_stub = stub_request(:post, /domain_transfers/).with(body: request_body, headers: headers, basic_auth: ['test_goodnames', 'testtest']) @@ -28,7 +28,7 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase def test_fail_gracefully body = { errors: [{ title: 'epic fail' }] }.to_json - headers = { 'Content-type' => 'application/json' } + headers = { 'Content-type' => Mime[:json] } stub_request(:post, /domain_transfers/).to_return(status: 400, body: body, headers: headers) visit registrar_domains_url diff --git a/test/system/registrar_area/bulk_change/nameserver_test.rb b/test/system/registrar_area/bulk_change/nameserver_test.rb index b3f4e70c1..d6b3170d5 100644 --- a/test/system/registrar_area/bulk_change/nameserver_test.rb +++ b/test/system/registrar_area/bulk_change/nameserver_test.rb @@ -12,7 +12,7 @@ class RegistrarAreaNameserverBulkChangeTest < ApplicationSystemTestCase ipv4: %w[192.0.2.55 192.0.2.56], ipv6: %w[2001:db8::55 2001:db8::56] } } } request_stub = stub_request(:put, /registrar\/nameservers/).with(body: request_body, - headers: { 'Content-type' => 'application/json' }, + headers: { 'Content-type' => Mime[:json] }, basic_auth: ['test_goodnames', 'testtest']) .to_return(body: { data: [{ type: 'nameserver', @@ -38,7 +38,7 @@ class RegistrarAreaNameserverBulkChangeTest < ApplicationSystemTestCase def test_fails_gracefully stub_request(:put, /registrar\/nameservers/).to_return(status: 400, body: { errors: [{ title: 'epic fail' }] }.to_json, - headers: { 'Content-type' => 'application/json' }) + headers: { 'Content-type' => Mime[:json] }) visit registrar_domains_url click_link 'Bulk change' 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 f14fc2208..c678e8f34 100644 --- a/test/system/registrar_area/bulk_change/tech_contact_test.rb +++ b/test/system/registrar_area/bulk_change/tech_contact_test.rb @@ -31,7 +31,7 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase stub_request(:patch, /domains\/contacts/) .to_return(status: 400, body: { error: { message: 'epic fail' } }.to_json, - headers: { 'Content-type' => 'application/json' }) + headers: { 'Content-type' => Mime[:json] }) visit registrar_domains_url click_link 'Bulk change' diff --git a/test/system/registrar_area/domains_test.rb b/test/system/registrar_area/domains_test.rb index db51d7096..7a2f5f7f1 100644 --- a/test/system/registrar_area/domains_test.rb +++ b/test/system/registrar_area/domains_test.rb @@ -15,7 +15,7 @@ class RegistrarDomainsTest < ApplicationSystemTestCase visit registrar_domains_url click_button 'Download CSV' - assert_equal 'attachment; filename="Domains_2010-07-05_10.30.csv"', response_headers['Content-Disposition'] + assert_equal "attachment; filename=\"Domains_2010-07-05_10.30.csv\"; filename*=UTF-8''Domains_2010-07-05_10.30.csv", response_headers['Content-Disposition'] assert_equal expected_csv, page.body end end diff --git a/test/system/registrar_area/invoices/new_invoice_payment_test.rb b/test/system/registrar_area/invoices/new_invoice_payment_test.rb index 6366a418d..ea4b924fe 100644 --- a/test/system/registrar_area/invoices/new_invoice_payment_test.rb +++ b/test/system/registrar_area/invoices/new_invoice_payment_test.rb @@ -26,7 +26,7 @@ class NewInvoicePaymentTest < ApplicationSystemTestCase def test_create_new_SEB_payment create_invoice_and_visit_its_page - click_link_or_button 'Seb' + click_link_or_button 'seb' form = page.find('form') assert_equal('https://www.seb.ee/cgi-bin/dv.sh/ipank.r', form['action']) assert_equal('post', form['method']) @@ -35,7 +35,7 @@ class NewInvoicePaymentTest < ApplicationSystemTestCase def test_create_new_Every_Pay_payment create_invoice_and_visit_its_page - click_link_or_button 'Every pay' + click_link_or_button 'every_pay' expected_hmac_fields = 'account_id,amount,api_username,callback_url,' + 'customer_url,hmac_fields,nonce,order_reference,timestamp,transaction_type' diff --git a/test/tasks/data_migrations/convert_domain_delete_date_test.rb b/test/tasks/data_migrations/convert_domain_delete_date_test.rb deleted file mode 100644 index a17e1109b..000000000 --- a/test/tasks/data_migrations/convert_domain_delete_date_test.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'test_helper' - -class ConvertDomainDeleteDateTaskTest < ActiveSupport::TestCase - setup do - @domain = domains(:shop) - end - - def test_moves_domain_delete_date_one_day_ahead - @domain.update!(delete_date: '2010-07-05') - - capture_io do - run_task - end - @domain.reload - - assert_equal Date.parse('2010-07-06'), @domain.delete_date - end - - def test_processes_invalid_domains - @domain = domains(:invalid) - @domain.update_columns(delete_date: '2010-07-05') - - capture_io do - run_task - end - @domain.reload - - assert_equal Date.parse('2010-07-06'), @domain.delete_date - end - - def test_skips_non_expired_domains - @domain.update!(delete_date: nil) - - assert_nothing_raised do - capture_io do - run_task - end - end - end - - def test_output - eliminate_effect_of_all_domains_except(@domain) - @domain.update!(delete_date: '2010-07-05') - - assert_output "Domains processed: 1\n" do - run_task - end - end - - private - - def eliminate_effect_of_all_domains_except(domain) - Domain.connection.disable_referential_integrity do - Domain.delete_all("id != #{domain.id}") - end - end - - def run_task - Rake::Task['data_migrations:convert_domain_delete_date'].execute - end -end \ No newline at end of file diff --git a/test/tasks/emails/verify_email_task_test.rb b/test/tasks/emails/verify_email_task_test.rb new file mode 100644 index 000000000..7cca11845 --- /dev/null +++ b/test/tasks/emails/verify_email_task_test.rb @@ -0,0 +1,63 @@ +require 'test_helper' + +class VerifyEmailTaskTest < ActiveSupport::TestCase + + def setup + @contact = contacts(:john) + @invalid_contact = contacts(:invalid_email) + @contact_verification = @contact.email_verification + @invalid_contact_verification = @invalid_contact.email_verification + + @default_whitelist = Truemail.configure.whitelisted_domains + @default_blacklist = Truemail.configure.blacklisted_domains + Truemail.configure.whitelisted_domains = whitelisted_domains + Truemail.configure.blacklisted_domains = blacklisted_domains + end + + def teardown + Truemail.configure.whitelisted_domains = @default_whitelist + Truemail.configure.blacklisted_domains = @default_blacklist + end + + def domain(email) + Mail::Address.new(email).domain + rescue Mail::Field::IncompleteParseError + nil + end + + def whitelisted_domains + [domain(@contact.email)].reject(&:blank?) + end + + def blacklisted_domains + [domain(@invalid_contact.email)].reject(&:blank?) + end + + def test_tasks_verifies_emails + capture_io { run_task } + + @contact_verification.reload + @invalid_contact_verification.reload + + assert @contact_verification.verified? + assert @invalid_contact_verification.failed? + end + + def test_domain_task_verifies_for_one_domain + capture_io { run_single_domain_task(@contact_verification.domain) } + + @contact_verification.reload + @invalid_contact_verification.reload + + assert @contact_verification.verified? + assert @invalid_contact_verification.not_verified? + end + + def run_task + Rake::Task['verify_email:all_domains'].execute + end + + def run_single_domain_task(domain) + Rake::Task["verify_email:domain"].invoke(domain) + end +end diff --git a/test/tasks/invoices/cancel_overdue_test.rb b/test/tasks/invoices/cancel_overdue_test.rb index 19ef8e0bf..044997ae9 100644 --- a/test/tasks/invoices/cancel_overdue_test.rb +++ b/test/tasks/invoices/cancel_overdue_test.rb @@ -31,7 +31,7 @@ class CancelOverdueInvoicesTaskTest < ActiveSupport::TestCase def eliminate_effect_of_other_invoices Invoice.connection.disable_referential_integrity do - Invoice.delete_all("id != #{@invoice.id}") + Invoice.where("id != #{@invoice.id}").delete_all end end diff --git a/test/tasks/invoices/process_payments_test.rb b/test/tasks/invoices/process_payments_test.rb index 8c3b6ec73..bd447be29 100644 --- a/test/tasks/invoices/process_payments_test.rb +++ b/test/tasks/invoices/process_payments_test.rb @@ -58,12 +58,42 @@ class ProcessPaymentsTaskTest < ActiveSupport::TestCase assert @invoice.paid? end + def test_attaches_paid_payment_order_to_invoice + assert @invoice.unpaid? + + capture_io { run_task } + @invoice.reload + + payment_order = @invoice.payment_orders.last + assert_equal 'PaymentOrders::SystemPayment', payment_order.type + assert payment_order.paid? + end + + def test_attaches_failed_payment_order_to_invoice + assert @invoice.unpaid? + account = accounts(:cash) + account.update!(registrar: registrars(:goodnames)) + + capture_io { run_task } + @invoice.reload + + payment_order = @invoice.payment_orders.last + assert_equal 'PaymentOrders::SystemPayment', payment_order.type + assert payment_order.failed? + end + def test_output assert_output "Transactions processed: 1\n" do run_task end end + def test_parses_keystore_properly + assert_nothing_raised do + run_task + end + end + private def run_task @@ -75,4 +105,4 @@ class ProcessPaymentsTaskTest < ActiveSupport::TestCase invoice.update!({ account_activity: nil, cancelled_at: nil }.merge(attributes)) invoice end -end \ No newline at end of file +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 1310fcaaf..1b70baf49 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -10,15 +10,22 @@ if ENV['COVERAGE'] end ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +require_relative '../config/environment' require 'rails/test_help' require 'minitest/mock' require 'capybara/rails' require 'capybara/minitest' require 'webmock/minitest' -require 'support/rails5_assertions' # Remove once upgraded to Rails 5 require 'support/assertions/epp_assertions' + +# `bin/rails test` is not the same as `bin/rake test`. +# All tasks will be loaded (and executed) twice when using the former without `Rake::Task.clear`. +# https://github.com/rails/rails/issues/28786 +require 'rake' +Rake::Task.clear +Rails.application.load_tasks + Setting.address_processing = false Setting.registry_country_code = 'US' @@ -40,13 +47,7 @@ class ActiveSupport::TestCase teardown do travel_back - end -end - -# Allows testing OPTIONS request just like GET or POST -module ActionDispatch::Integration::RequestHelpers - def options(path, parameters = nil, headers_or_env = nil) - process :options, path, parameters, headers_or_env + Setting.address_processing = false end end @@ -60,9 +61,14 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest WebMock.reset! Capybara.reset_sessions! Capybara.use_default_driver + Setting.address_processing = false end end class EppTestCase < ActionDispatch::IntegrationTest include Assertions::EppAssertions + + teardown do + Setting.address_processing = false + end end