From 075f68e06ce5c80acf9bbba68bcbad06f9fb4bed Mon Sep 17 00:00:00 2001 From: Zach Denton Date: Thu, 4 Aug 2022 21:57:42 -0400 Subject: [PATCH] Update code for IT3. (#2412) --- .../platform/server/app/admin/it3_profiles.rb | 54 ++++++ .../platform/server/app/admin/it3_surveys.rb | 41 ++++ ecosystem/platform/server/app/admin/users.rb | 4 +- .../server/app/components/header_component.rb | 2 +- .../app/controllers/discourse_controller.rb | 2 +- .../controllers/it2_profiles_controller.rb | 174 ----------------- .../app/controllers/it2_surveys_controller.rb | 61 ------ .../controllers/it3_profiles_controller.rb | 175 ++++++++++++++++++ .../app/controllers/it3_surveys_controller.rb | 61 ++++++ ...{it2s_controller.rb => it3s_controller.rb} | 22 +-- .../app/controllers/onboarding_controller.rb | 20 +- .../app/controllers/static_page_controller.rb | 2 +- .../users/confirmations_controller.rb | 2 +- .../controllers/users/sessions_controller.rb | 2 +- .../server/app/helpers/genesis_helper.rb | 42 ++--- .../server/app/helpers/it2_surveys_helper.rb | 7 - .../app/jobs/discourse_add_group_job.rb | 2 +- .../server/app/jobs/it2_final_check_job.rb | 31 ---- .../server/app/jobs/it3_final_check_job.rb | 31 ++++ .../server/app/jobs/kyc_complete_job.rb | 2 +- .../platform/server/app/jobs/location_job.rb | 22 +-- ecosystem/platform/server/app/jobs/nhc_job.rb | 32 ++-- .../platform/server/app/models/it2_profile.rb | 14 -- .../platform/server/app/models/it3_profile.rb | 96 ++++++++++ .../platform/server/app/models/it3_survey.rb | 15 ++ ecosystem/platform/server/app/models/user.rb | 12 +- .../app/views/devise/sessions/new.html.erb | 2 +- .../_form.html.erb | 20 +- .../edit.html.erb | 2 +- .../new.html.erb | 2 +- .../_form.html.erb | 10 +- .../edit.html.erb | 2 +- .../{it2_surveys => it3_surveys}/new.html.erb | 2 +- .../app/views/{it2s => it3s}/show.html.erb | 6 +- .../layouts/{it2.html.erb => it3.html.erb} | 10 +- ...it2_intro.html.erb => _it3_intro.html.erb} | 2 +- .../app/views/static_page/community.html.erb | 2 +- ecosystem/platform/server/config/routes.rb | 7 +- .../20220801175155_create_it3_profiles.rb | 35 ++++ .../20220801175454_create_it3_surveys.rb | 19 ++ ecosystem/platform/server/db/schema.rb | 49 ++++- .../server/spec/factories/it3_profiles.rb | 22 +++ .../server/spec/factories/it3_surveys.rb | 15 ++ ...est.rb => it3_profiles_controller_test.rb} | 33 ++-- .../controllers/settings_controller_test.rb | 2 + 45 files changed, 753 insertions(+), 417 deletions(-) create mode 100644 ecosystem/platform/server/app/admin/it3_profiles.rb create mode 100644 ecosystem/platform/server/app/admin/it3_surveys.rb delete mode 100644 ecosystem/platform/server/app/controllers/it2_profiles_controller.rb delete mode 100644 ecosystem/platform/server/app/controllers/it2_surveys_controller.rb create mode 100644 ecosystem/platform/server/app/controllers/it3_profiles_controller.rb create mode 100644 ecosystem/platform/server/app/controllers/it3_surveys_controller.rb rename ecosystem/platform/server/app/controllers/{it2s_controller.rb => it3s_controller.rb} (65%) delete mode 100644 ecosystem/platform/server/app/helpers/it2_surveys_helper.rb delete mode 100644 ecosystem/platform/server/app/jobs/it2_final_check_job.rb create mode 100644 ecosystem/platform/server/app/jobs/it3_final_check_job.rb create mode 100644 ecosystem/platform/server/app/models/it3_profile.rb create mode 100644 ecosystem/platform/server/app/models/it3_survey.rb rename ecosystem/platform/server/app/views/{it2_profiles => it3_profiles}/_form.html.erb (89%) rename ecosystem/platform/server/app/views/{it2_profiles => it3_profiles}/edit.html.erb (85%) rename ecosystem/platform/server/app/views/{it2_profiles => it3_profiles}/new.html.erb (85%) rename ecosystem/platform/server/app/views/{it2_surveys => it3_surveys}/_form.html.erb (86%) rename ecosystem/platform/server/app/views/{it2_surveys => it3_surveys}/edit.html.erb (53%) rename ecosystem/platform/server/app/views/{it2_surveys => it3_surveys}/new.html.erb (53%) rename ecosystem/platform/server/app/views/{it2s => it3s}/show.html.erb (96%) rename ecosystem/platform/server/app/views/layouts/{it2.html.erb => it3.html.erb} (85%) rename ecosystem/platform/server/app/views/shared/{_it2_intro.html.erb => _it3_intro.html.erb} (84%) create mode 100644 ecosystem/platform/server/db/migrate/20220801175155_create_it3_profiles.rb create mode 100644 ecosystem/platform/server/db/migrate/20220801175454_create_it3_surveys.rb create mode 100644 ecosystem/platform/server/spec/factories/it3_profiles.rb create mode 100644 ecosystem/platform/server/spec/factories/it3_surveys.rb rename ecosystem/platform/server/test/controllers/{it2_profiles_controller_test.rb => it3_profiles_controller_test.rb} (58%) diff --git a/ecosystem/platform/server/app/admin/it3_profiles.rb b/ecosystem/platform/server/app/admin/it3_profiles.rb new file mode 100644 index 0000000000000..5e11bf82ab5e1 --- /dev/null +++ b/ecosystem/platform/server/app/admin/it3_profiles.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +ActiveAdmin.register It3Profile do + menu priority: 2 + actions :all, except: %i[destroy edit new] + + permit_params :consensus_key + includes :user + + index do + selectable_column + id_column + column :user + column :owner_key + column :consensus_key + column :account_key + column :network_key + column :validator_ip + column :validator_address + column :validator_port + column :validator_metrics_port + column :validator_api_port + column :validator_verified + column :fullnode_address + column :fullnode_port + column :fullnode_network_key + column :created_at + column :updated_at + actions + end + + filter :owner_key + filter :consensus_key + filter :account_key + filter :network_key + filter :validator_ip + filter :validator_address + filter :validator_port + filter :validator_metrics_port + filter :validator_api_port + filter :validator_verified + filter :created_at + filter :updated_at + + show do + default_main_content do + row :location + row(:it3_survey) { |profile| profile.user.it3_survey } + end + end +end diff --git a/ecosystem/platform/server/app/admin/it3_surveys.rb b/ecosystem/platform/server/app/admin/it3_surveys.rb new file mode 100644 index 0000000000000..1818b6b7c53a2 --- /dev/null +++ b/ecosystem/platform/server/app/admin/it3_surveys.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +ActiveAdmin.register It3Survey do + menu priority: 2 + actions :all, except: %i[destroy edit new] + + permit_params :consensus_key + includes :user + + index do + selectable_column + id_column + column :user + column :persona + column :participate_reason + column :qualified_reason + column :website + column :interest_reason + column :created_at + column :updated_at + actions + end + + filter :user_id + filter :persona + filter :participate_reason + filter :qualified_reason + filter :website + filter :interest_reason + filter :created_at + filter :updated_at + + show do + default_main_content do + row(:it3_profile) { |survey| survey.user.it3_profile } + end + end +end diff --git a/ecosystem/platform/server/app/admin/users.rb b/ecosystem/platform/server/app/admin/users.rb index 77a802df5e95f..9ac0b5314f6bb 100644 --- a/ecosystem/platform/server/app/admin/users.rb +++ b/ecosystem/platform/server/app/admin/users.rb @@ -8,13 +8,14 @@ actions :all, except: %i[destroy new] permit_params :email, :is_root, :kyc_exempt - includes :authorizations, :it1_profile, :it2_profile + includes :authorizations, :it1_profile, :it2_profile, :it3_profile index do selectable_column id_column column :it1_profile column :it2_profile + column :it3_profile column :authorizations column 'External ID', :external_id column :email @@ -42,6 +43,7 @@ row :authorizations row :it1_profile row :it2_profile + row :it3_profile end end diff --git a/ecosystem/platform/server/app/components/header_component.rb b/ecosystem/platform/server/app/components/header_component.rb index 3d1c7ff5dbbd3..4f7b97c6bc1aa 100644 --- a/ecosystem/platform/server/app/components/header_component.rb +++ b/ecosystem/platform/server/app/components/header_component.rb @@ -13,7 +13,7 @@ class HeaderComponent < ViewComponent::Base [ NavItem.new('/community', 'Aptos Community', 'Aptos Community'), NavItem.new('/it1', 'AIT1', 'Incentivized Testnet 1 Results'), - NavItem.new('/it2', 'AIT2', 'Incentivized Testnet 2'), + NavItem.new('/it2', 'AIT2', 'Incentivized Testnet 2 Results'), NavItem.new('https://forum.aptoslabs.com/', 'Forum', 'Aptos Forum') ] ), diff --git a/ecosystem/platform/server/app/controllers/discourse_controller.rb b/ecosystem/platform/server/app/controllers/discourse_controller.rb index ed43a063d29da..1db6a3d726fec 100644 --- a/ecosystem/platform/server/app/controllers/discourse_controller.rb +++ b/ecosystem/platform/server/app/controllers/discourse_controller.rb @@ -33,7 +33,7 @@ def sso sso.admin = current_user.is_root? add_groups = [] - add_groups.append('ait2_eligible') if current_user.ait2_registration_complete? + add_groups.append('ait3_eligible') if current_user.ait3_registration_complete? sso.add_groups = add_groups if add_groups.present? redirect_to sso.to_url(DiscourseHelper.discourse_url('/session/sso_login')), allow_other_host: true diff --git a/ecosystem/platform/server/app/controllers/it2_profiles_controller.rb b/ecosystem/platform/server/app/controllers/it2_profiles_controller.rb deleted file mode 100644 index 513d76b35fc3e..0000000000000 --- a/ecosystem/platform/server/app/controllers/it2_profiles_controller.rb +++ /dev/null @@ -1,174 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) Aptos -# SPDX-License-Identifier: Apache-2.0 - -class It2ProfilesController < ApplicationController - before_action :authenticate_user! - before_action :ensure_registration_enabled! - before_action :ensure_confirmed! - before_action :set_it2_profile, only: %i[show edit update destroy] - respond_to :html - - def show - redirect_to edit_it2_profile_path(params.fetch(:id)) - end - - # GET /it2_profiles/new - def new - redirect_to edit_it2_profile_path(current_user.it2_profile) if current_user.it2_profile.present? - @it2_profile = It2Profile.new - end - - # GET /it2_profiles/1/edit - def edit; end - - # POST /it2_profiles or /it2_profiles.json - def create - params = it2_profile_params - params[:user] = current_user - @it2_profile = It2Profile.new(params) - - return unless check_recaptcha - - v = NodeHelper::NodeVerifier.new(@it2_profile.validator_address, - @it2_profile.validator_metrics_port, - @it2_profile.validator_api_port) - - if v.ip.ok - @it2_profile.validator_ip = v.ip.ip - else - @it2_profile.errors.add :validator_address, v.ip.message - respond_with(@it2_profile, status: :unprocessable_entity) and return - end - - if @it2_profile.save - log @it2_profile, 'created' - - if Flipper.enabled?(:node_health_checker) - @it2_profile.enqueue_nhc_job(true) - else - validate_node(v, do_location: true) - end - - if @it2_profile.validator_verified? - current_user.maybe_send_ait2_registration_complete_email - redirect_to it2_path, notice: 'AIT2 application completed successfully: your node is verified!' and return - end - end - respond_with(@it2_profile, status: :unprocessable_entity) - end - - # PATCH/PUT /it2_profiles/1 or /it2_profiles/1.json - def update - v = NodeHelper::NodeVerifier.new(it2_profile_params[:validator_address], - it2_profile_params[:validator_metrics_port], - it2_profile_params[:validator_api_port]) - - return unless check_recaptcha - - if v.ip.ok - @it2_profile.validator_ip = v.ip.ip - else - @it2_profile.errors.add :validator_address, v.ip.message - respond_with(@it2_profile, status: :unprocessable_entity) and return - end - - ip_changed = @it2_profile.validator_ip_changed? - if @it2_profile.update(it2_profile_params) - log @it2_profile, 'updated' - if @it2_profile.validator_verified? && !@it2_profile.needs_revalidation? - redirect_to it2_path, - notice: 'AIT2 node information updated' and return - end - - if Flipper.enabled?(:node_health_checker) - @it2_profile.enqueue_nhc_job(ip_changed) - else - validate_node(v, do_location: ip_changed) - end - - if @it2_profile.validator_verified? - redirect_to it2_path, notice: 'AIT2 node verification completed successfully!' and return - end - end - respond_with(@it2_profile, status: :unprocessable_entity) - end - - private - - # @param [NodeHelper::NodeVerifier] node_verifier - # @return [Array] - def validate_node(node_verifier, do_location: false) - results = node_verifier.verify - - # Save without validation to avoid needless uniqueness checks - is_valid = results.map(&:valid).all? - @it2_profile.update_attribute(:validator_verified, is_valid) - - LocationJob.perform_later({ it2_profile_id: @it2_profile.id }) if is_valid && do_location - - results.each do |result| - @it2_profile.errors.add :base, result.message unless result.valid - end - results - end - - def validate_node_nhc(node_verifier, do_location: false) - results = node_verifier.verify(ENV.fetch('NODE_CHECKER_BASELINE_CONFIG')) - - unless results.ok - @it2_profile.update_attribute(:validator_verified, false) - @it2_profile.errors.add :base, results.message - return results - end - - # Save without validation to avoid needless uniqueness checks - is_valid = results.evaluation_results.map { |r| r.score == 100 }.all? - @it2_profile.update_attribute(:validator_verified, is_valid) - - LocationJob.perform_later({ it2_profile_id: @it2_profile.id }) if is_valid && do_location - - results.evaluation_results.each do |result| - next unless result.score < 100 - - message = "#{result.category}: #{result.evaluator_name} - #{result.score}\n" \ - "#{result.headline}:\n" \ - "#{result.explanation}\n" \ - "#{result.links}\n" - @it2_profile.errors.add :base, message - end - results - end - - def check_recaptcha - recaptcha_v3_success = verify_recaptcha(action: 'it2/update', minimum_score: 0.5, - secret_key: ENV.fetch('RECAPTCHA_V3_SECRET_KEY', nil), model: @it2_profile) - recaptcha_v2_success = verify_recaptcha(model: @it2_profile) unless recaptcha_v3_success - unless recaptcha_v3_success || recaptcha_v2_success - @show_recaptcha_v2 = true - respond_with(@it2_profile, status: :unprocessable_entity) - return false - end - true - end - - # Use callbacks to share common setup or constraints between actions. - def set_it2_profile - @it2_profile = It2Profile.find(params[:id]) - head :forbidden unless @it2_profile.user_id == current_user.id - end - - # Only allow a list of trusted parameters through. - def it2_profile_params - params.fetch(:it2_profile, {}).permit(:consensus_key, :account_key, :network_key, :validator_address, - :validator_port, :validator_api_port, :validator_metrics_port, - :fullnode_address, :fullnode_port, :fullnode_network_key, :terms_accepted) - end - - def ensure_registration_enabled! - redirect_to root_path unless Flipper.enabled?(:it2_registration_open) - redirect_to it2_path if Flipper.enabled?(:it2_node_registration_disabled, - current_user) || Flipper.enabled?(:it2_registration_closed, current_user) - end -end diff --git a/ecosystem/platform/server/app/controllers/it2_surveys_controller.rb b/ecosystem/platform/server/app/controllers/it2_surveys_controller.rb deleted file mode 100644 index 44155228ec90b..0000000000000 --- a/ecosystem/platform/server/app/controllers/it2_surveys_controller.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) Aptos -# SPDX-License-Identifier: Apache-2.0 - -class It2SurveysController < ApplicationController - before_action :authenticate_user! - before_action :ensure_confirmed! - before_action :set_it2_survey, only: %i[show edit update destroy] - layout 'it2' - respond_to :html - - def show - redirect_to edit_it2_survey_path(params.fetch(:id)) - end - - # GET /it2_surveys/new - def new - redirect_to edit_it2_survey_path(current_user.it2_survey) if current_user.it2_survey.present? - @it2_survey = It2Survey.new - end - - # GET /it2_surveys/1/edit - def edit; end - - # POST /it2_surveys - def create - params = it2_survey_params - params[:user] = current_user - @it2_survey = It2Survey.new(params) - - if @it2_survey.save - log @it2_survey, 'created' - redirect_to it2_path, notice: 'Your survey response has been recorded.' - else - respond_with(@it2_survey, status: :unprocessable_entity) - end - end - - # PATCH/PUT /it2_surveys/1 - def update - if @it2_survey.update(it2_survey_params) - log @it2_survey, 'updated' - redirect_to it2_path, notice: 'Survey response updated.' - else - respond_with(@it2_survey, status: :unprocessable_entity) - end - end - - private - - def set_it2_survey - @it2_survey = It2Survey.find(params[:id]) - head :forbidden unless @it2_survey.user_id == current_user.id - end - - def it2_survey_params - params.require(:it2_survey).permit(:user_id, :persona, :participate_reason, :qualified_reason, :website, - :interest_reason) - end -end diff --git a/ecosystem/platform/server/app/controllers/it3_profiles_controller.rb b/ecosystem/platform/server/app/controllers/it3_profiles_controller.rb new file mode 100644 index 0000000000000..a68d58facca04 --- /dev/null +++ b/ecosystem/platform/server/app/controllers/it3_profiles_controller.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +class It3ProfilesController < ApplicationController + before_action :authenticate_user! + before_action :ensure_registration_enabled! + before_action :ensure_confirmed! + before_action :set_it3_profile, only: %i[show edit update destroy] + respond_to :html + + def show + redirect_to edit_it3_profile_path(params.fetch(:id)) + end + + # GET /it3_profiles/new + def new + redirect_to edit_it3_profile_path(current_user.it3_profile) if current_user.it3_profile.present? + @it3_profile = It3Profile.new + end + + # GET /it3_profiles/1/edit + def edit; end + + # POST /it3_profiles or /it3_profiles.json + def create + params = it3_profile_params + params[:user] = current_user + @it3_profile = It3Profile.new(params) + + return unless check_recaptcha + + v = NodeHelper::NodeVerifier.new(@it3_profile.validator_address, + @it3_profile.validator_metrics_port, + @it3_profile.validator_api_port) + + if v.ip.ok + @it3_profile.validator_ip = v.ip.ip + else + @it3_profile.errors.add :validator_address, v.ip.message + respond_with(@it3_profile, status: :unprocessable_entity) and return + end + + if @it3_profile.save + log @it3_profile, 'created' + + if Flipper.enabled?(:node_health_checker) + @it3_profile.enqueue_nhc_job(true) + else + validate_node(v, do_location: true) + end + + if @it3_profile.validator_verified? + current_user.maybe_send_ait3_registration_complete_email + redirect_to it3_path, notice: 'AIT3 application completed successfully: your node is verified!' and return + end + end + respond_with(@it3_profile, status: :unprocessable_entity) + end + + # PATCH/PUT /it3_profiles/1 or /it3_profiles/1.json + def update + v = NodeHelper::NodeVerifier.new(it3_profile_params[:validator_address], + it3_profile_params[:validator_metrics_port], + it3_profile_params[:validator_api_port]) + + return unless check_recaptcha + + if v.ip.ok + @it3_profile.validator_ip = v.ip.ip + else + @it3_profile.errors.add :validator_address, v.ip.message + respond_with(@it3_profile, status: :unprocessable_entity) and return + end + + ip_changed = @it3_profile.validator_ip_changed? + if @it3_profile.update(it3_profile_params) + log @it3_profile, 'updated' + if @it3_profile.validator_verified? && !@it3_profile.needs_revalidation? + redirect_to it3_path, + notice: 'AIT3 node information updated' and return + end + + if Flipper.enabled?(:node_health_checker) + @it3_profile.enqueue_nhc_job(ip_changed) + else + validate_node(v, do_location: ip_changed) + end + + if @it3_profile.validator_verified? + redirect_to it3_path, notice: 'AIT3 node verification completed successfully!' and return + end + end + respond_with(@it3_profile, status: :unprocessable_entity) + end + + private + + # @param [NodeHelper::NodeVerifier] node_verifier + # @return [Array] + def validate_node(node_verifier, do_location: false) + results = node_verifier.verify + + # Save without validation to avoid needless uniqueness checks + is_valid = results.map(&:valid).all? + @it3_profile.update_attribute(:validator_verified, is_valid) + + LocationJob.perform_later({ it3_profile_id: @it3_profile.id }) if is_valid && do_location + + results.each do |result| + @it3_profile.errors.add :base, result.message unless result.valid + end + results + end + + def validate_node_nhc(node_verifier, do_location: false) + results = node_verifier.verify(ENV.fetch('NODE_CHECKER_BASELINE_CONFIG')) + + unless results.ok + @it3_profile.update_attribute(:validator_verified, false) + @it3_profile.errors.add :base, results.message + return results + end + + # Save without validation to avoid needless uniqueness checks + is_valid = results.evaluation_results.map { |r| r.score == 100 }.all? + @it3_profile.update_attribute(:validator_verified, is_valid) + + LocationJob.perform_later({ it3_profile_id: @it3_profile.id }) if is_valid && do_location + + results.evaluation_results.each do |result| + next unless result.score < 100 + + message = "#{result.category}: #{result.evaluator_name} - #{result.score}\n" \ + "#{result.headline}:\n" \ + "#{result.explanation}\n" \ + "#{result.links}\n" + @it3_profile.errors.add :base, message + end + results + end + + def check_recaptcha + recaptcha_v3_success = verify_recaptcha(action: 'it3/update', minimum_score: 0.5, + secret_key: ENV.fetch('RECAPTCHA_V3_SECRET_KEY', nil), model: @it3_profile) + recaptcha_v2_success = verify_recaptcha(model: @it3_profile) unless recaptcha_v3_success + unless recaptcha_v3_success || recaptcha_v2_success + @show_recaptcha_v2 = true + respond_with(@it3_profile, status: :unprocessable_entity) + return false + end + true + end + + # Use callbacks to share common setup or constraints between actions. + def set_it3_profile + @it3_profile = It3Profile.find(params[:id]) + head :forbidden unless @it3_profile.user_id == current_user.id + end + + # Only allow a list of trusted parameters through. + def it3_profile_params + params.fetch(:it3_profile, {}).permit(:owner_key, + :consensus_key, :account_key, :network_key, :validator_address, + :validator_port, :validator_api_port, :validator_metrics_port, + :fullnode_address, :fullnode_port, :fullnode_network_key, :terms_accepted) + end + + def ensure_registration_enabled! + redirect_to root_path unless Flipper.enabled?(:it3_registration_open) + redirect_to it3_path if Flipper.enabled?(:it3_node_registration_disabled, + current_user) || Flipper.enabled?(:it3_registration_closed, current_user) + end +end diff --git a/ecosystem/platform/server/app/controllers/it3_surveys_controller.rb b/ecosystem/platform/server/app/controllers/it3_surveys_controller.rb new file mode 100644 index 0000000000000..018c00c02c74a --- /dev/null +++ b/ecosystem/platform/server/app/controllers/it3_surveys_controller.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +class It3SurveysController < ApplicationController + before_action :authenticate_user! + before_action :ensure_confirmed! + before_action :set_it3_survey, only: %i[show edit update destroy] + layout 'it3' + respond_to :html + + def show + redirect_to edit_it3_survey_path(params.fetch(:id)) + end + + # GET /it3_surveys/new + def new + redirect_to edit_it3_survey_path(current_user.it3_survey) if current_user.it3_survey.present? + @it3_survey = It3Survey.new + end + + # GET /it3_surveys/1/edit + def edit; end + + # POST /it3_surveys + def create + params = it3_survey_params + params[:user] = current_user + @it3_survey = It3Survey.new(params) + + if @it3_survey.save + log @it3_survey, 'created' + redirect_to it3_path, notice: 'Your survey response has been recorded.' + else + respond_with(@it3_survey, status: :unprocessable_entity) + end + end + + # PATCH/PUT /it3_surveys/1 + def update + if @it3_survey.update(it3_survey_params) + log @it3_survey, 'updated' + redirect_to it3_path, notice: 'Survey response updated.' + else + respond_with(@it3_survey, status: :unprocessable_entity) + end + end + + private + + def set_it3_survey + @it3_survey = It3Survey.find(params[:id]) + head :forbidden unless @it3_survey.user_id == current_user.id + end + + def it3_survey_params + params.require(:it3_survey).permit(:user_id, :persona, :participate_reason, :qualified_reason, :website, + :interest_reason) + end +end diff --git a/ecosystem/platform/server/app/controllers/it2s_controller.rb b/ecosystem/platform/server/app/controllers/it3s_controller.rb similarity index 65% rename from ecosystem/platform/server/app/controllers/it2s_controller.rb rename to ecosystem/platform/server/app/controllers/it3s_controller.rb index ae8564e3d32b0..0e027b803e7ba 100644 --- a/ecosystem/platform/server/app/controllers/it2s_controller.rb +++ b/ecosystem/platform/server/app/controllers/it3s_controller.rb @@ -3,15 +3,15 @@ # Copyright (c) Aptos # SPDX-License-Identifier: Apache-2.0 -class It2sController < ApplicationController - layout 'it2' +class It3sController < ApplicationController + layout 'it3' before_action :ensure_confirmed! def show redirect_to root_path unless user_signed_in? - redirect_to root_path unless Flipper.enabled?(:it2_registration_open) - @it2_registration_closed = Flipper.enabled?(:it2_registration_closed, current_user) + redirect_to root_path unless Flipper.enabled?(:it3_registration_open) + @it3_registration_closed = Flipper.enabled?(:it3_registration_closed, current_user) @steps = [ connect_discord_step, survey_step, @@ -24,7 +24,7 @@ def show end first_incomplete = @steps.index { |step| !step.completed } @steps[first_incomplete + 1..].each { |step| step.disabled = true } if first_incomplete - @steps.each { |step| step.disabled = true } if @it2_registration_closed + @steps.each { |step| step.disabled = true } if @it3_registration_closed end private @@ -39,22 +39,22 @@ def connect_discord_step end def survey_step - completed = !current_user.it2_survey.nil? + completed = !current_user.it3_survey.nil? { name: :survey, - disabled: Flipper.enabled?(:it2_node_registration_disabled, current_user), + disabled: Flipper.enabled?(:it3_node_registration_disabled, current_user), completed:, - href: completed ? edit_it2_survey_path(current_user.it2_survey) : new_it2_survey_path + href: completed ? edit_it3_survey_path(current_user.it3_survey) : new_it3_survey_path } end def node_registration_step - completed = !!current_user.it2_profile&.validator_verified? + completed = !!current_user.it3_profile&.validator_verified? { name: :node_registration, completed:, - disabled: Flipper.enabled?(:it2_node_registration_disabled, current_user), - href: completed ? edit_it2_profile_path(current_user.it2_profile) : new_it2_profile_path + disabled: Flipper.enabled?(:it3_node_registration_disabled, current_user), + href: completed ? edit_it3_profile_path(current_user.it3_profile) : new_it3_profile_path } end diff --git a/ecosystem/platform/server/app/controllers/onboarding_controller.rb b/ecosystem/platform/server/app/controllers/onboarding_controller.rb index e4a27a64af61c..e3fc1521cbd3a 100644 --- a/ecosystem/platform/server/app/controllers/onboarding_controller.rb +++ b/ecosystem/platform/server/app/controllers/onboarding_controller.rb @@ -7,11 +7,11 @@ class OnboardingController < ApplicationController before_action :authenticate_user!, except: %i[kyc_callback] before_action :ensure_discord!, only: %i[kyc_redirect] before_action :ensure_confirmed!, only: %i[kyc_redirect] - before_action :ensure_it2_registration_open!, only: %i[kyc_callback kyc_redirect] + before_action :ensure_it3_registration_open!, only: %i[kyc_callback kyc_redirect] before_action :set_oauth_data, except: %i[kyc_callback] protect_from_forgery except: :kyc_callback - layout 'it2' + layout 'it3' def email redirect_to it2_path if current_user.registration_completed? @@ -50,16 +50,16 @@ def email_update def kyc_redirect if current_user.kyc_exempt? - redirect_to it2_path, + redirect_to it3_path, notice: 'You are not required to complete Identity Verification' and return end if current_user.kyc_complete? - redirect_to it2_path, + redirect_to it3_path, notice: 'You have already completed Identity Verification' and return end - unless current_user.it2_profile&.validator_verified? - path = current_user.it2_profile.present? ? edit_it2_profile_path(current_user.it2_profile) : new_it2_profile_path + unless current_user.it3_profile&.validator_verified? + path = current_user.it3_profile.present? ? edit_it3_profile_path(current_user.it3_profile) : new_it3_profile_path redirect_to path, error: 'Must register and validate node first' and return end @@ -87,10 +87,10 @@ def kyc_callback inquiry_id = kyc_params.require(:'inquiry-id') begin KYCCompleteJob.perform_now({ user_id: current_user&.id, inquiry_id:, external_id: reference_id }) - redirect_to it2_path, notice: 'Identity Verification completed successfully!' + redirect_to it3_path, notice: 'Identity Verification completed successfully!' rescue KYCCompleteJobError => e Sentry.capture_exception(e) - redirect_to it2_path, error: 'Error; If you completed Identity Verification, ' \ + redirect_to it3_path, error: 'Error; If you completed Identity Verification, ' \ "it may take some time to reflect. Error: #{e}" end end @@ -102,7 +102,7 @@ def set_oauth_data @oauth_email = current_user.authorizations.pluck(:email).first end - def ensure_it2_registration_open! - redirect_to leaderboard_it2_path if Flipper.enabled?(:it2_registration_closed, current_user) + def ensure_it3_registration_open! + redirect_to leaderboard_it3_path if Flipper.enabled?(:it3_registration_closed, current_user) end end diff --git a/ecosystem/platform/server/app/controllers/static_page_controller.rb b/ecosystem/platform/server/app/controllers/static_page_controller.rb index 84de7e259751a..d59aafa493207 100644 --- a/ecosystem/platform/server/app/controllers/static_page_controller.rb +++ b/ecosystem/platform/server/app/controllers/static_page_controller.rb @@ -4,7 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 class StaticPageController < ApplicationController - layout 'it2', only: [:community] + layout 'it3', only: [:community] def root; end diff --git a/ecosystem/platform/server/app/controllers/users/confirmations_controller.rb b/ecosystem/platform/server/app/controllers/users/confirmations_controller.rb index 461d2c81560c2..e55b26456ed3b 100644 --- a/ecosystem/platform/server/app/controllers/users/confirmations_controller.rb +++ b/ecosystem/platform/server/app/controllers/users/confirmations_controller.rb @@ -5,7 +5,7 @@ module Users class ConfirmationsController < Devise::ConfirmationsController - layout 'it2' + layout 'it3' # GET /resource/confirmation?confirmation_token=abcdef def show diff --git a/ecosystem/platform/server/app/controllers/users/sessions_controller.rb b/ecosystem/platform/server/app/controllers/users/sessions_controller.rb index 1d867b39dd65b..2a873996e114c 100644 --- a/ecosystem/platform/server/app/controllers/users/sessions_controller.rb +++ b/ecosystem/platform/server/app/controllers/users/sessions_controller.rb @@ -5,6 +5,6 @@ module Users class SessionsController < Devise::SessionsController - layout 'it2', only: %i[new] + layout 'it3', only: %i[new] end end diff --git a/ecosystem/platform/server/app/helpers/genesis_helper.rb b/ecosystem/platform/server/app/helpers/genesis_helper.rb index f640a15c1289b..cf28d4ff1091c 100644 --- a/ecosystem/platform/server/app/helpers/genesis_helper.rb +++ b/ecosystem/platform/server/app/helpers/genesis_helper.rb @@ -25,45 +25,45 @@ class Creator # @param [Array] user_ids # @return [GenesisHelper::Creator] def self.from_user_ids(user_ids) - new(It2Profile.where(user_id: user_ids)) + new(It3Profile.where(user_id: user_ids)) end - # @param [It2Profile] it2_profile - def self.convert_profile_to_obj(it2_profile) + # @param [It3Profile] it3_profile + def self.convert_profile_to_obj(it3_profile) data = { - account_address: it2_profile.account_address.delete_prefix('0x'), - consensus_key: it2_profile.consensus_key, - account_key: it2_profile.account_key, - validator_network_key: it2_profile.network_key, + account_address: it3_profile.account_address.delete_prefix('0x'), + consensus_key: it3_profile.consensus_key, + account_key: it3_profile.account_key, + validator_network_key: it3_profile.network_key, validator_host: { - host: it2_profile.validator_address, - port: it2_profile.validator_port + host: it3_profile.validator_address, + port: it3_profile.validator_port }, stake_amount: 1 } - if it2_profile.fullnode_network_key.present? - data[:full_node_network_key] = it2_profile.fullnode_network_key + if it3_profile.fullnode_network_key.present? + data[:full_node_network_key] = it3_profile.fullnode_network_key data[:full_node_host] = { - host: it2_profile.fullnode_address, - port: it2_profile.fullnode_port + host: it3_profile.fullnode_address, + port: it3_profile.fullnode_port } else # Fallback - data[:full_node_network_key] = it2_profile.network_key + data[:full_node_network_key] = it3_profile.network_key end data end - def self.convert_profile_to_yaml(it2_profile) - convert_profile_to_obj(it2_profile).deep_stringify_keys.to_yaml + def self.convert_profile_to_yaml(it3_profile) + convert_profile_to_obj(it3_profile).deep_stringify_keys.to_yaml end - # @param [Array] it2_profiles - def initialize(it2_profiles) - @it2_profiles = it2_profiles + # @param [Array] it3_profiles + def initialize(it3_profiles) + @it3_profiles = it3_profiles @yamls = {} - @it2_profiles.each do |it2_profile| - @yamls[it2_profile.account_address] = self.class.convert_profile_to_yaml it2_profile + @it3_profiles.each do |it3_profile| + @yamls[it3_profile.account_address] = self.class.convert_profile_to_yaml it3_profile end end diff --git a/ecosystem/platform/server/app/helpers/it2_surveys_helper.rb b/ecosystem/platform/server/app/helpers/it2_surveys_helper.rb deleted file mode 100644 index 4bd7dda269b9b..0000000000000 --- a/ecosystem/platform/server/app/helpers/it2_surveys_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) Aptos -# SPDX-License-Identifier: Apache-2.0 - -module It2SurveysHelper -end diff --git a/ecosystem/platform/server/app/jobs/discourse_add_group_job.rb b/ecosystem/platform/server/app/jobs/discourse_add_group_job.rb index 6f0edd59fea82..a7bb94bdd5c1e 100644 --- a/ecosystem/platform/server/app/jobs/discourse_add_group_job.rb +++ b/ecosystem/platform/server/app/jobs/discourse_add_group_job.rb @@ -37,4 +37,4 @@ def add_group end end -# DiscourseAddGroupJob.perform_now({ user_id: 4, group_name: "ait2_eligible" }) +# DiscourseAddGroupJob.perform_now({ user_id: 4, group_name: "ait3_eligible" }) diff --git a/ecosystem/platform/server/app/jobs/it2_final_check_job.rb b/ecosystem/platform/server/app/jobs/it2_final_check_job.rb deleted file mode 100644 index 399bdbd32b97d..0000000000000 --- a/ecosystem/platform/server/app/jobs/it2_final_check_job.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -# Copyright (c) Aptos -# SPDX-License-Identifier: Apache-2.0 - -class It2FinalCheckError < StandardError; end - -class It2FinalCheckJob < ApplicationJob - # Ex args: { it2_profile_id: 32 } - def perform(args) - it2_profile = It2Profile.find(args[:it2_profile_id]) - sentry_scope.set_user(id: it2_profile.user_id) - sentry_scope.set_context(:job_info, { validator_address: it2_profile.validator_address }) - - node_verifier = NodeHelper::NodeVerifier.new(it2_profile.validator_address, it2_profile.validator_metrics_port, 0) - - unless node_verifier.ip.ok - it2_profile.update(validator_verified_final: false) - raise It2FinalCheckError, - "Error fetching IP for #{it2_profile.validator_address}: #{node_verifier.ip.message}" - end - - res = node_verifier.fetch_json_metrics - unless res.ok - it2_profile.update(validator_verified_final: false) - raise It2FinalCheckError, "Error fetching metrics json for '#{it2_profile.validator_ip}': #{res.message}" - end - - it2_profile.update(validator_verified_final: true, metrics_data: res.data) - end -end diff --git a/ecosystem/platform/server/app/jobs/it3_final_check_job.rb b/ecosystem/platform/server/app/jobs/it3_final_check_job.rb new file mode 100644 index 0000000000000..6bf481587720a --- /dev/null +++ b/ecosystem/platform/server/app/jobs/it3_final_check_job.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +class It3FinalCheckError < StandardError; end + +class It3FinalCheckJob < ApplicationJob + # Ex args: { it3_profile_id: 32 } + def perform(args) + it3_profile = It3Profile.find(args[:it3_profile_id]) + sentry_scope.set_user(id: it3_profile.user_id) + sentry_scope.set_context(:job_info, { validator_address: it3_profile.validator_address }) + + node_verifier = NodeHelper::NodeVerifier.new(it3_profile.validator_address, it3_profile.validator_metrics_port, 0) + + unless node_verifier.ip.ok + it3_profile.update(validator_verified_final: false) + raise It3FinalCheckError, + "Error fetching IP for #{it3_profile.validator_address}: #{node_verifier.ip.message}" + end + + res = node_verifier.fetch_json_metrics + unless res.ok + it3_profile.update(validator_verified_final: false) + raise It3FinalCheckError, "Error fetching metrics json for '#{it3_profile.validator_ip}': #{res.message}" + end + + it3_profile.update(validator_verified_final: true, metrics_data: res.data) + end +end diff --git a/ecosystem/platform/server/app/jobs/kyc_complete_job.rb b/ecosystem/platform/server/app/jobs/kyc_complete_job.rb index 4e45e0838bc2c..7036703f85885 100644 --- a/ecosystem/platform/server/app/jobs/kyc_complete_job.rb +++ b/ecosystem/platform/server/app/jobs/kyc_complete_job.rb @@ -34,6 +34,6 @@ def perform(args) raise KYCCompleteJobError, "Inquiry was not complete! Status: '#{status}'" unless VALID_STATUSES.include? status user.update(completed_persona_inquiry_id: inquiry_id, kyc_status: 'completed') - user.maybe_send_ait2_registration_complete_email + user.maybe_send_ait3_registration_complete_email end end diff --git a/ecosystem/platform/server/app/jobs/location_job.rb b/ecosystem/platform/server/app/jobs/location_job.rb index a5612376e392b..1285b6ed066c4 100644 --- a/ecosystem/platform/server/app/jobs/location_job.rb +++ b/ecosystem/platform/server/app/jobs/location_job.rb @@ -6,32 +6,32 @@ class LocationFetchError < StandardError; end class LocationJob < ApplicationJob - # Ex args: { it2_profile_id: 32 } + # Ex args: { it3_profile_id: 32 } def perform(args) - it2_profile = It2Profile.find(args[:it2_profile_id]) - sentry_scope.set_user(id: it2_profile.user_id) - sentry_scope.set_context(:job_info, { validator_address: it2_profile.validator_address }) + it3_profile = It3Profile.find(args[:it3_profile_id]) + sentry_scope.set_user(id: it3_profile.user_id) + sentry_scope.set_context(:job_info, { validator_address: it3_profile.validator_address }) # pass zeroes as a hack here: we only need the validator address - ip_resolver = NodeHelper::IPResolver.new(it2_profile.validator_address) + ip_resolver = NodeHelper::IPResolver.new(it3_profile.validator_address) unless ip_resolver.ip.ok raise LocationFetchError, - "Error fetching IP for #{it2_profile.validator_address}: #{ip_resolver.ip.message}" + "Error fetching IP for #{it3_profile.validator_address}: #{ip_resolver.ip.message}" end new_ip = ip_resolver.ip.ip.to_s - if new_ip != it2_profile.validator_ip - Rails.logger.warn "IP does not match one in profile for it2_profile ##{it2_profile.id} - " \ - "#{it2_profile.validator_address}: was #{it2_profile.validator_ip}, got #{new_ip}" + if new_ip != it3_profile.validator_ip + Rails.logger.warn "IP does not match one in profile for it3_profile ##{it3_profile.id} - " \ + "#{it3_profile.validator_address}: was #{it3_profile.validator_ip}, got #{new_ip}" end location_res = ip_resolver.location unless location_res.ok # TODO: DO SOMETHING (SENTRY? THROW?) IF THIS IS NOT OK - raise LocationFetchError, "Error fetching location for '#{it2_profile.validator_ip}': #{location_res.message}" + raise LocationFetchError, "Error fetching location for '#{it3_profile.validator_ip}': #{location_res.message}" end - Location.upsert_from_maxmind!(it2_profile, location_res.record) + Location.upsert_from_maxmind!(it3_profile, location_res.record) end end diff --git a/ecosystem/platform/server/app/jobs/nhc_job.rb b/ecosystem/platform/server/app/jobs/nhc_job.rb index fef39e1e3363c..04ba844229ece 100644 --- a/ecosystem/platform/server/app/jobs/nhc_job.rb +++ b/ecosystem/platform/server/app/jobs/nhc_job.rb @@ -4,23 +4,23 @@ # SPDX-License-Identifier: Apache-2.0 class NhcJob < ApplicationJob - # Ex args: { it2_profile_id: 32, do_location: true } + # Ex args: { it3_profile_id: 32, do_location: true } def perform(args) - @it2_profile = It2Profile.find(args[:it2_profile_id]) + @it3_profile = It3Profile.find(args[:it3_profile_id]) do_location = args[:do_location] - sentry_scope.set_user(id: @it2_profile.user_id) - sentry_scope.set_context(:job_info, { validator_address: @it2_profile.validator_address }) + sentry_scope.set_user(id: @it3_profile.user_id) + sentry_scope.set_context(:job_info, { validator_address: @it3_profile.validator_address }) nhc = NodeHelper::NodeChecker.new(ENV.fetch('NODE_CHECKER_BASE_URL'), - @it2_profile.validator_address, - @it2_profile.validator_metrics_port, - @it2_profile.validator_api_port, - @it2_profile.validator_port) + @it3_profile.validator_address, + @it3_profile.validator_metrics_port, + @it3_profile.validator_api_port, + @it3_profile.validator_port) - @it2_profile.update_attribute(:validator_verified, false) + @it3_profile.update_attribute(:validator_verified, false) unless nhc.ip.ok - write_status("Error fetching IP for #{@it2_profile.validator_address}: #{nhc.ip.message}") + write_status("Error fetching IP for #{@it3_profile.validator_address}: #{nhc.ip.message}") return end @@ -33,12 +33,12 @@ def perform(args) # Save without validation to avoid needless uniqueness checks is_valid = results.evaluation_results.map { |r| r.score == 100 }.all? - @it2_profile.validator_verified = is_valid + @it3_profile.validator_verified = is_valid if is_valid write_status('Node validated successfully!') - @it2_profile.user.maybe_send_ait2_registration_complete_email - LocationJob.perform_later({ it2_profile_id: @it2_profile.id }) if do_location + @it3_profile.user.maybe_send_ait3_registration_complete_email + LocationJob.perform_later({ it3_profile_id: @it3_profile.id }) if do_location return end @@ -57,8 +57,8 @@ def perform(args) end def write_status(status) - @it2_profile.nhc_job_id = nil - @it2_profile.nhc_output = status - @it2_profile.save! + @it3_profile.nhc_job_id = nil + @it3_profile.nhc_output = status + @it3_profile.save! end end diff --git a/ecosystem/platform/server/app/models/it2_profile.rb b/ecosystem/platform/server/app/models/it2_profile.rb index b47c901244efa..9686dce400dd8 100644 --- a/ecosystem/platform/server/app/models/it2_profile.rb +++ b/ecosystem/platform/server/app/models/it2_profile.rb @@ -55,20 +55,6 @@ def nhc_job_running? nhc_job_id.present? end - def enqueue_nhc_job(do_location) - return unless id.present? - - if nhc_job_running? - errors.add :base, 'Node Health Checker Job already enqueued' - return - end - - job = NhcJob.perform_later({ it2_profile_id: id, do_location: }) - self.nhc_job_id = job.job_id&.presence || 'default-job-id' - self.nhc_output = nil - update_columns(nhc_job_id:, nhc_output: nil) - end - def fullnode_network_key=(value) value = nil if value.blank? super(value) diff --git a/ecosystem/platform/server/app/models/it3_profile.rb b/ecosystem/platform/server/app/models/it3_profile.rb new file mode 100644 index 0000000000000..29e289f3ba7f9 --- /dev/null +++ b/ecosystem/platform/server/app/models/it3_profile.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +require 'set' +require 'resolv' + +class It3Profile < ApplicationRecord + belongs_to :user + validates :user_id, uniqueness: true + + has_one :location, as: :item + + validates :owner_key, presence: true, uniqueness: true, format: { with: /\A0x[a-f0-9]{64}\z/i } + validates :consensus_key, presence: true, uniqueness: true, format: { with: /\A0x[a-f0-9]{64}\z/i } + validates :account_key, presence: true, uniqueness: true, format: { with: /\A0x[a-f0-9]{64}\z/i } + validates :network_key, presence: true, uniqueness: true, format: { with: /\A0x[a-f0-9]{64}\z/i } + + validates :validator_address, presence: true + validates :validator_port, presence: true, numericality: { only_integer: true } + validates :validator_api_port, presence: true, numericality: { only_integer: true } + validates :validator_metrics_port, presence: true, numericality: { only_integer: true } + + validates :fullnode_port, numericality: { only_integer: true }, allow_nil: true + validates :fullnode_network_key, uniqueness: true, format: { with: /\A0x[a-f0-9]{64}\z/i }, allow_nil: true, + allow_blank: true + + validates :terms_accepted, acceptance: true + + validate :check_validator_ipv4 + + before_save :maybe_set_validated_to_false + before_save :set_account_address + + CHANGES_TO_REVALIDATE = Set.new %w[consensus_key account_key network_key validator_address validator_api_port + validator_metrics_port] + + def validator_port + self[:validator_port] || 6180 + end + + def validator_api_port + self[:validator_api_port] || 8080 + end + + def validator_metrics_port + self[:validator_metrics_port] || 9101 + end + + def needs_revalidation? + changed.map { |field| CHANGES_TO_REVALIDATE.include? field }.any? + end + + def nhc_job_running? + nhc_job_id.present? + end + + def enqueue_nhc_job(do_location) + return unless id.present? + + if nhc_job_running? + errors.add :base, 'Node Health Checker Job already enqueued' + return + end + + job = NhcJob.perform_later({ it3_profile_id: id, do_location: }) + self.nhc_job_id = job.job_id&.presence || 'default-job-id' + self.nhc_output = nil + update_columns(nhc_job_id:, nhc_output: nil) + end + + def fullnode_network_key=(value) + value = nil if value.blank? + super(value) + end + + private + + def set_account_address + self.account_address = self.class.address_from_key account_key + end + + def check_validator_ipv4 + # If the updates don't require revalidation, don't do it + return unless validator_ip_changed? + + return if validator_ip.blank? || validator_ip =~ Resolv::IPv4::Regex + + errors.add :validator_address, 'Address must resolve to or be an IPv4' + end + + def maybe_set_validated_to_false + self.validator_verified = false if needs_revalidation? + end +end diff --git a/ecosystem/platform/server/app/models/it3_survey.rb b/ecosystem/platform/server/app/models/it3_survey.rb new file mode 100644 index 0000000000000..ed199294670b2 --- /dev/null +++ b/ecosystem/platform/server/app/models/it3_survey.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Copyright (c) Aptos +# SPDX-License-Identifier: Apache-2.0 + +class It3Survey < ApplicationRecord + belongs_to :user + validates :user_id, uniqueness: true + + validates :persona, presence: true + validates :participate_reason, presence: true + validates :qualified_reason, presence: true + validates :website, format: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_nil: true, allow_blank: true + validates :interest_reason, presence: true +end diff --git a/ecosystem/platform/server/app/models/user.rb b/ecosystem/platform/server/app/models/user.rb index 8c48608e8e067..9b361e1e92b1f 100644 --- a/ecosystem/platform/server/app/models/user.rb +++ b/ecosystem/platform/server/app/models/user.rb @@ -27,6 +27,8 @@ class User < ApplicationRecord has_one :it1_profile, dependent: :destroy has_one :it2_profile, dependent: :destroy has_one :it2_survey, dependent: :destroy + has_one :it3_profile, dependent: :destroy + has_one :it3_survey, dependent: :destroy before_save :maybe_enqueue_forum_sync @@ -69,15 +71,15 @@ def self.create_new_user_from_oauth(auth) # end # end - def maybe_send_ait2_registration_complete_email - return unless ait2_registration_complete? + def maybe_send_ait3_registration_complete_email + return unless ait3_registration_complete? SendRegistrationCompleteEmailJob.perform_now({ user_id: id }) - DiscourseAddGroupJob.perform_later({ user_id: id, group_name: 'ait2_eligible' }) + DiscourseAddGroupJob.perform_later({ user_id: id, group_name: 'ait3_eligible' }) end - def ait2_registration_complete? - kyc_complete? && it2_profile&.validator_verified? + def ait3_registration_complete? + kyc_complete? && it3_profile&.validator_verified? end def kyc_complete? diff --git a/ecosystem/platform/server/app/views/devise/sessions/new.html.erb b/ecosystem/platform/server/app/views/devise/sessions/new.html.erb index 47ce5bf876266..031092f9609d6 100644 --- a/ecosystem/platform/server/app/views/devise/sessions/new.html.erb +++ b/ecosystem/platform/server/app/views/devise/sessions/new.html.erb @@ -2,7 +2,7 @@
<%= render 'layouts/flash' %> - <%= render 'shared/it2_intro' %> + <%= render 'shared/it3_intro' %>

Log in

diff --git a/ecosystem/platform/server/app/views/it2_profiles/_form.html.erb b/ecosystem/platform/server/app/views/it3_profiles/_form.html.erb similarity index 89% rename from ecosystem/platform/server/app/views/it2_profiles/_form.html.erb rename to ecosystem/platform/server/app/views/it3_profiles/_form.html.erb index eeeb8614f5681..87a0d95fc62cf 100644 --- a/ecosystem/platform/server/app/views/it2_profiles/_form.html.erb +++ b/ecosystem/platform/server/app/views/it3_profiles/_form.html.erb @@ -1,13 +1,13 @@
- <%= form_with(model: it2_profile, class: 'flex basis-full flex-col md:flex-row md:gap-10 md:justify-between', data: { turbo: !@show_recaptcha_v2, controller: 'recaptcha', action: 'recaptcha#validate' }, builder: AptosFormBuilder) do |f| %> + <%= form_with(model: it3_profile, class: 'flex basis-full flex-col md:flex-row md:gap-10 md:justify-between', data: { turbo: !@show_recaptcha_v2, controller: 'recaptcha', action: 'recaptcha#validate' }, builder: AptosFormBuilder) do |f| %>
- <% if it2_profile.errors.any? %> + <% if it3_profile.errors.any? %> diff --git a/ecosystem/platform/server/app/views/it2_surveys/_form.html.erb b/ecosystem/platform/server/app/views/it3_surveys/_form.html.erb similarity index 86% rename from ecosystem/platform/server/app/views/it2_surveys/_form.html.erb rename to ecosystem/platform/server/app/views/it3_surveys/_form.html.erb index a72aae6cb0796..de584224c5b36 100644 --- a/ecosystem/platform/server/app/views/it2_surveys/_form.html.erb +++ b/ecosystem/platform/server/app/views/it3_surveys/_form.html.erb @@ -1,11 +1,11 @@ -<%= form_with(model: it2_survey, builder: AptosFormBuilder) do |form| %> - <% if it2_survey.errors.any? %> +<%= form_with(model: it3_survey, builder: AptosFormBuilder) do |form| %> + <% if it3_survey.errors.any? %>