about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/settings/migration/redirects_controller.rb45
-rw-r--r--app/controllers/settings/migrations_controller.rb9
-rw-r--r--app/models/account_migration.rb3
-rw-r--r--app/models/form/redirect.rb47
-rw-r--r--app/views/auth/registrations/edit.html.haml11
-rw-r--r--app/views/settings/migration/redirects/new.html.haml27
-rw-r--r--app/views/settings/migrations/show.html.haml10
7 files changed, 138 insertions, 14 deletions
diff --git a/app/controllers/settings/migration/redirects_controller.rb b/app/controllers/settings/migration/redirects_controller.rb
new file mode 100644
index 000000000..6e5b72ffb
--- /dev/null
+++ b/app/controllers/settings/migration/redirects_controller.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class Settings::Migration::RedirectsController < Settings::BaseController
+  layout 'admin'
+
+  before_action :authenticate_user!
+  before_action :require_not_suspended!
+
+  skip_before_action :require_functional!
+
+  def new
+    @redirect = Form::Redirect.new
+  end
+
+  def create
+    @redirect = Form::Redirect.new(resource_params.merge(account: current_account))
+
+    if @redirect.valid_with_challenge?(current_user)
+      current_account.update!(moved_to_account: @redirect.target_account)
+      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+      redirect_to settings_migration_path, notice: I18n.t('migrations.moved_msg', acct: current_account.moved_to_account.acct)
+    else
+      render :new
+    end
+  end
+
+  def destroy
+    if current_account.moved_to_account_id.present?
+      current_account.update!(moved_to_account: nil)
+      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
+    end
+
+    redirect_to settings_migration_path, notice: I18n.t('migrations.cancelled_msg')
+  end
+
+  private
+
+  def resource_params
+    params.require(:form_redirect).permit(:acct, :current_password, :current_username)
+  end
+
+  def require_not_suspended!
+    forbidden if current_account.suspended?
+  end
+end
diff --git a/app/controllers/settings/migrations_controller.rb b/app/controllers/settings/migrations_controller.rb
index 90092c692..00bde1d61 100644
--- a/app/controllers/settings/migrations_controller.rb
+++ b/app/controllers/settings/migrations_controller.rb
@@ -27,15 +27,6 @@ class Settings::MigrationsController < Settings::BaseController
     end
   end
 
-  def cancel
-    if current_account.moved_to_account_id.present?
-      current_account.update!(moved_to_account: nil)
-      ActivityPub::UpdateDistributionWorker.perform_async(current_account.id)
-    end
-
-    redirect_to settings_migration_path, notice: I18n.t('migrations.cancelled_msg')
-  end
-
   helper_method :on_cooldown?
 
   private
diff --git a/app/models/account_migration.rb b/app/models/account_migration.rb
index e2c2cb085..681b5b2cd 100644
--- a/app/models/account_migration.rb
+++ b/app/models/account_migration.rb
@@ -47,8 +47,7 @@ class AccountMigration < ApplicationRecord
   end
 
   def acct=(val)
-    val = val.to_s.strip
-    super(val.start_with?('@') ? val[1..-1] : val)
+    super(val.to_s.strip.gsub(/\A@/, ''))
   end
 
   private
diff --git a/app/models/form/redirect.rb b/app/models/form/redirect.rb
new file mode 100644
index 000000000..a7961f8e8
--- /dev/null
+++ b/app/models/form/redirect.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+class Form::Redirect
+  include ActiveModel::Model
+
+  attr_accessor :account, :target_account, :current_password,
+                :current_username
+
+  attr_reader :acct
+
+  validates :acct, presence: true, domain: { acct: true }
+  validate :validate_target_account
+
+  def valid_with_challenge?(current_user)
+    if current_user.encrypted_password.present?
+      errors.add(:current_password, :invalid) unless current_user.valid_password?(current_password)
+    else
+      errors.add(:current_username, :invalid) unless account.username == current_username
+    end
+
+    return false unless errors.empty?
+
+    set_target_account
+    valid?
+  end
+
+  def acct=(val)
+    @acct = val.to_s.strip.gsub(/\A@/, '')
+  end
+
+  private
+
+  def set_target_account
+    @target_account = ResolveAccountService.new.call(acct)
+  rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error
+    # Validation will take care of it
+  end
+
+  def validate_target_account
+    if target_account.nil?
+      errors.add(:acct, I18n.t('migrations.errors.not_found'))
+    else
+      errors.add(:acct, I18n.t('migrations.errors.already_moved')) if account.moved_to_account_id.present? && account.moved_to_account_id == target_account.id
+      errors.add(:acct, I18n.t('migrations.errors.move_to_self')) if account.id == target_account.id
+    end
+  end
+end
diff --git a/app/views/auth/registrations/edit.html.haml b/app/views/auth/registrations/edit.html.haml
index 885171c58..a155c75c9 100644
--- a/app/views/auth/registrations/edit.html.haml
+++ b/app/views/auth/registrations/edit.html.haml
@@ -30,7 +30,18 @@
 
 = render 'sessions'
 
+%hr.spacer/
+
+%h3= t('auth.migrate_account')
+%p.muted-hint= t('auth.migrate_account_html', path: settings_migration_path)
+
+%hr.spacer/
+
+%h3= t('migrations.incoming_migrations')
+%p.muted-hint= t('migrations.incoming_migrations_html', path: settings_aliases_path)
+
 - if open_deletion? && !current_account.suspended?
   %hr.spacer/
+
   %h3= t('auth.delete_account')
   %p.muted-hint= t('auth.delete_account_html', path: settings_delete_path)
diff --git a/app/views/settings/migration/redirects/new.html.haml b/app/views/settings/migration/redirects/new.html.haml
new file mode 100644
index 000000000..017450f4b
--- /dev/null
+++ b/app/views/settings/migration/redirects/new.html.haml
@@ -0,0 +1,27 @@
+- content_for :page_title do
+  = t('settings.migrate')
+
+= simple_form_for @redirect, url: settings_migration_redirect_path do |f|
+  %p.hint= t('migrations.warning.before')
+
+  %ul.hint
+    %li.warning-hint= t('migrations.warning.redirect')
+    %li.warning-hint= t('migrations.warning.other_data')
+    %li.warning-hint= t('migrations.warning.disabled_account')
+
+  %hr.spacer/
+
+  = render 'shared/error_messages', object: @redirect
+
+  .fields-row
+    .fields-row__column.fields-group.fields-row__column-6
+      = f.input :acct, wrapper: :with_block_label, input_html: { autocapitalize: 'none', autocorrect: 'off' }, label: t('simple_form.labels.account_migration.acct'), hint: t('simple_form.hints.account_migration.acct')
+
+    .fields-row__column.fields-group.fields-row__column-6
+      - if current_user.encrypted_password.present?
+        = f.input :current_password, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
+      - else
+        = f.input :current_username, wrapper: :with_block_label, input_html: { :autocomplete => 'off' }, required: true
+
+  .actions
+    = f.button :button, t('migrations.set_redirect'), type: :submit, class: 'button button--destructive'
diff --git a/app/views/settings/migrations/show.html.haml b/app/views/settings/migrations/show.html.haml
index 1e5c47726..078eaebc6 100644
--- a/app/views/settings/migrations/show.html.haml
+++ b/app/views/settings/migrations/show.html.haml
@@ -12,28 +12,32 @@
 
         %p.hint= t('migrations.cancel_explanation')
 
-        %p.hint= link_to t('migrations.cancel'), cancel_settings_migration_path, data: { method: :post }
+        %p.hint= link_to t('migrations.cancel'), settings_migration_redirect_path, data: { method: :delete }
   - else
     %p.hint
       %span.positive-hint= t('migrations.not_redirecting')
 
 %hr.spacer/
 
-%h3= t 'migrations.proceed_with_move'
+%h3= t('auth.migrate_account')
 
 = simple_form_for @migration, url: settings_migration_path do |f|
   - if on_cooldown?
-    %span.warning-hint= t('migrations.on_cooldown', count: ((@cooldown.cooldown_at - Time.now.utc) / 1.day.seconds).ceil)
+    %p.hint
+      %span.warning-hint= t('migrations.on_cooldown', count: ((@cooldown.cooldown_at - Time.now.utc) / 1.day.seconds).ceil)
   - else
     %p.hint= t('migrations.warning.before')
 
     %ul.hint
       %li.warning-hint= t('migrations.warning.followers')
+      %li.warning-hint= t('migrations.warning.redirect')
       %li.warning-hint= t('migrations.warning.other_data')
       %li.warning-hint= t('migrations.warning.backreference_required')
       %li.warning-hint= t('migrations.warning.cooldown')
       %li.warning-hint= t('migrations.warning.disabled_account')
 
+  %p.hint= t('migrations.warning.only_redirect_html', path: new_settings_migration_redirect_path)
+
   %hr.spacer/
 
   = render 'shared/error_messages', object: @migration