浏览代码

Add account migration configurable, but enabled by default

Daniel Supernault 1 年之前
父节点
当前提交
4a6be62128

+ 62 - 53
app/Http/Controllers/Admin/AdminSettingsController.php

@@ -2,18 +2,18 @@
 
 
 namespace App\Http\Controllers\Admin;
 namespace App\Http\Controllers\Admin;
 
 
-use Artisan, Cache, DB;
-use Illuminate\Http\Request;
-use Carbon\Carbon;
-use App\{Comment, Like, Media, Page, Profile, Report, Status, User};
-use App\Models\InstanceActor;
-use App\Http\Controllers\Controller;
-use App\Util\Lexer\PrettyNumber;
 use App\Models\ConfigCache;
 use App\Models\ConfigCache;
+use App\Models\InstanceActor;
+use App\Page;
+use App\Profile;
 use App\Services\AccountService;
 use App\Services\AccountService;
 use App\Services\ConfigCacheService;
 use App\Services\ConfigCacheService;
+use App\User;
 use App\Util\Site\Config;
 use App\Util\Site\Config;
-use Illuminate\Support\Str;
+use Artisan;
+use Cache;
+use DB;
+use Illuminate\Http\Request;
 
 
 trait AdminSettingsController
 trait AdminSettingsController
 {
 {
@@ -21,7 +21,7 @@ trait AdminSettingsController
     {
     {
         $cloud_storage = ConfigCacheService::get('pixelfed.cloud_storage');
         $cloud_storage = ConfigCacheService::get('pixelfed.cloud_storage');
         $cloud_disk = config('filesystems.cloud');
         $cloud_disk = config('filesystems.cloud');
-        $cloud_ready = !empty(config('filesystems.disks.' . $cloud_disk . '.key')) && !empty(config('filesystems.disks.' . $cloud_disk . '.secret'));
+        $cloud_ready = ! empty(config('filesystems.disks.'.$cloud_disk.'.key')) && ! empty(config('filesystems.disks.'.$cloud_disk.'.secret'));
         $types = explode(',', ConfigCacheService::get('pixelfed.media_types'));
         $types = explode(',', ConfigCacheService::get('pixelfed.media_types'));
         $rules = ConfigCacheService::get('app.rules') ? json_decode(ConfigCacheService::get('app.rules'), true) : null;
         $rules = ConfigCacheService::get('app.rules') ? json_decode(ConfigCacheService::get('app.rules'), true) : null;
         $jpeg = in_array('image/jpg', $types) || in_array('image/jpeg', $types);
         $jpeg = in_array('image/jpg', $types) || in_array('image/jpeg', $types);
@@ -35,6 +35,7 @@ trait AdminSettingsController
         $openReg = (bool) config_cache('pixelfed.open_registration');
         $openReg = (bool) config_cache('pixelfed.open_registration');
         $curOnboarding = (bool) config_cache('instance.curated_registration.enabled');
         $curOnboarding = (bool) config_cache('instance.curated_registration.enabled');
         $regState = $openReg ? 'open' : ($curOnboarding ? 'filtered' : 'closed');
         $regState = $openReg ? 'open' : ($curOnboarding ? 'filtered' : 'closed');
+        $accountMigration = (bool) config_cache('federation.migration');
 
 
         return view('admin.settings.home', compact(
         return view('admin.settings.home', compact(
             'jpeg',
             'jpeg',
@@ -48,7 +49,8 @@ trait AdminSettingsController
             'cloud_ready',
             'cloud_ready',
             'availableAdmins',
             'availableAdmins',
             'currentAdmin',
             'currentAdmin',
-            'regState'
+            'regState',
+            'accountMigration'
         ));
         ));
     }
     }
 
 
@@ -67,41 +69,42 @@ trait AdminSettingsController
             'type_mp4' => 'nullable',
             'type_mp4' => 'nullable',
             'type_webp' => 'nullable',
             'type_webp' => 'nullable',
             'admin_account_id' => 'nullable',
             'admin_account_id' => 'nullable',
-            'regs' => 'required|in:open,filtered,closed'
+            'regs' => 'required|in:open,filtered,closed',
+            'account_migration' => 'nullable',
         ]);
         ]);
 
 
         $orb = false;
         $orb = false;
         $cob = false;
         $cob = false;
-        switch($request->input('regs')) {
+        switch ($request->input('regs')) {
             case 'open':
             case 'open':
                 $orb = true;
                 $orb = true;
                 $cob = false;
                 $cob = false;
-            break;
+                break;
 
 
             case 'filtered':
             case 'filtered':
                 $orb = false;
                 $orb = false;
                 $cob = true;
                 $cob = true;
-            break;
+                break;
 
 
             case 'closed':
             case 'closed':
                 $orb = false;
                 $orb = false;
                 $cob = false;
                 $cob = false;
-            break;
+                break;
         }
         }
 
 
         ConfigCacheService::put('pixelfed.open_registration', (bool) $orb);
         ConfigCacheService::put('pixelfed.open_registration', (bool) $orb);
         ConfigCacheService::put('instance.curated_registration.enabled', (bool) $cob);
         ConfigCacheService::put('instance.curated_registration.enabled', (bool) $cob);
 
 
-        if($request->filled('admin_account_id')) {
+        if ($request->filled('admin_account_id')) {
             ConfigCacheService::put('instance.admin.pid', $request->admin_account_id);
             ConfigCacheService::put('instance.admin.pid', $request->admin_account_id);
             Cache::forget('api:v1:instance-data:contact');
             Cache::forget('api:v1:instance-data:contact');
             Cache::forget('api:v1:instance-data-response-v1');
             Cache::forget('api:v1:instance-data-response-v1');
         }
         }
-        if($request->filled('rule_delete')) {
+        if ($request->filled('rule_delete')) {
             $index = (int) $request->input('rule_delete');
             $index = (int) $request->input('rule_delete');
             $rules = ConfigCacheService::get('app.rules');
             $rules = ConfigCacheService::get('app.rules');
             $json = json_decode($rules, true);
             $json = json_decode($rules, true);
-            if(!$rules || empty($json)) {
+            if (! $rules || empty($json)) {
                 return;
                 return;
             }
             }
             unset($json[$index]);
             unset($json[$index]);
@@ -109,6 +112,7 @@ trait AdminSettingsController
             ConfigCacheService::put('app.rules', $json);
             ConfigCacheService::put('app.rules', $json);
             Cache::forget('api:v1:instance-data:rules');
             Cache::forget('api:v1:instance-data:rules');
             Cache::forget('api:v1:instance-data-response-v1');
             Cache::forget('api:v1:instance-data-response-v1');
+
             return 200;
             return 200;
         }
         }
 
 
@@ -124,8 +128,8 @@ trait AdminSettingsController
         ];
         ];
 
 
         foreach ($mimes as $key => $value) {
         foreach ($mimes as $key => $value) {
-            if($request->input($key) == 'on') {
-                if(!in_array($value, $media_types)) {
+            if ($request->input($key) == 'on') {
+                if (! in_array($value, $media_types)) {
                     array_push($media_types, $value);
                     array_push($media_types, $value);
                 }
                 }
             } else {
             } else {
@@ -133,7 +137,7 @@ trait AdminSettingsController
             }
             }
         }
         }
 
 
-        if($media_types !== $media_types_original) {
+        if ($media_types !== $media_types_original) {
             ConfigCacheService::put('pixelfed.media_types', implode(',', array_unique($media_types)));
             ConfigCacheService::put('pixelfed.media_types', implode(',', array_unique($media_types)));
         }
         }
 
 
@@ -147,15 +151,15 @@ trait AdminSettingsController
             'account_limit' => 'pixelfed.max_account_size',
             'account_limit' => 'pixelfed.max_account_size',
             'custom_css' => 'uikit.custom.css',
             'custom_css' => 'uikit.custom.css',
             'custom_js' => 'uikit.custom.js',
             'custom_js' => 'uikit.custom.js',
-            'about_title' => 'about.title'
+            'about_title' => 'about.title',
         ];
         ];
 
 
         foreach ($keys as $key => $value) {
         foreach ($keys as $key => $value) {
             $cc = ConfigCache::whereK($value)->first();
             $cc = ConfigCache::whereK($value)->first();
             $val = $request->input($key);
             $val = $request->input($key);
-            if($cc && $cc->v != $val) {
+            if ($cc && $cc->v != $val) {
                 ConfigCacheService::put($value, $val);
                 ConfigCacheService::put($value, $val);
-            } else if(!empty($val)) {
+            } elseif (! empty($val)) {
                 ConfigCacheService::put($value, $val);
                 ConfigCacheService::put($value, $val);
             }
             }
         }
         }
@@ -175,33 +179,34 @@ trait AdminSettingsController
             'account_autofollow' => 'account.autofollow',
             'account_autofollow' => 'account.autofollow',
             'show_directory' => 'instance.landing.show_directory',
             'show_directory' => 'instance.landing.show_directory',
             'show_explore_feed' => 'instance.landing.show_explore',
             'show_explore_feed' => 'instance.landing.show_explore',
+            'account_migration' => 'federation.migration',
         ];
         ];
 
 
         foreach ($bools as $key => $value) {
         foreach ($bools as $key => $value) {
             $active = $request->input($key) == 'on';
             $active = $request->input($key) == 'on';
 
 
-            if($key == 'activitypub' && $active && !InstanceActor::exists()) {
+            if ($key == 'activitypub' && $active && ! InstanceActor::exists()) {
                 Artisan::call('instance:actor');
                 Artisan::call('instance:actor');
             }
             }
 
 
-            if( $key == 'mobile_apis' &&
+            if ($key == 'mobile_apis' &&
                 $active &&
                 $active &&
-                !file_exists(storage_path('oauth-public.key')) &&
-                !file_exists(storage_path('oauth-private.key'))
+                ! file_exists(storage_path('oauth-public.key')) &&
+                ! file_exists(storage_path('oauth-private.key'))
             ) {
             ) {
                 Artisan::call('passport:keys');
                 Artisan::call('passport:keys');
                 Artisan::call('route:cache');
                 Artisan::call('route:cache');
             }
             }
 
 
-            if(config_cache($value) !== $active) {
+            if (config_cache($value) !== $active) {
                 ConfigCacheService::put($value, (bool) $active);
                 ConfigCacheService::put($value, (bool) $active);
             }
             }
         }
         }
 
 
-        if($request->filled('new_rule')) {
+        if ($request->filled('new_rule')) {
             $rules = ConfigCacheService::get('app.rules');
             $rules = ConfigCacheService::get('app.rules');
             $val = $request->input('new_rule');
             $val = $request->input('new_rule');
-            if(!$rules) {
+            if (! $rules) {
                 ConfigCacheService::put('app.rules', json_encode([$val]));
                 ConfigCacheService::put('app.rules', json_encode([$val]));
             } else {
             } else {
                 $json = json_decode($rules, true);
                 $json = json_decode($rules, true);
@@ -212,13 +217,13 @@ trait AdminSettingsController
             Cache::forget('api:v1:instance-data-response-v1');
             Cache::forget('api:v1:instance-data-response-v1');
         }
         }
 
 
-        if($request->filled('account_autofollow_usernames')) {
+        if ($request->filled('account_autofollow_usernames')) {
             $usernames = explode(',', $request->input('account_autofollow_usernames'));
             $usernames = explode(',', $request->input('account_autofollow_usernames'));
             $names = [];
             $names = [];
 
 
-            foreach($usernames as $n) {
+            foreach ($usernames as $n) {
                 $p = Profile::whereUsername($n)->first();
                 $p = Profile::whereUsername($n)->first();
-                if(!$p) {
+                if (! $p) {
                     continue;
                     continue;
                 }
                 }
                 array_push($names, $p->username);
                 array_push($names, $p->username);
@@ -236,6 +241,7 @@ trait AdminSettingsController
     {
     {
         $path = storage_path('app/'.config('app.name'));
         $path = storage_path('app/'.config('app.name'));
         $files = is_dir($path) ? new \DirectoryIterator($path) : [];
         $files = is_dir($path) ? new \DirectoryIterator($path) : [];
+
         return view('admin.settings.backups', compact('files'));
         return view('admin.settings.backups', compact('files'));
     }
     }
 
 
@@ -247,6 +253,7 @@ trait AdminSettingsController
     public function settingsStorage(Request $request)
     public function settingsStorage(Request $request)
     {
     {
         $storage = [];
         $storage = [];
+
         return view('admin.settings.storage', compact('storage'));
         return view('admin.settings.storage', compact('storage'));
     }
     }
 
 
@@ -258,6 +265,7 @@ trait AdminSettingsController
     public function settingsPages(Request $request)
     public function settingsPages(Request $request)
     {
     {
         $pages = Page::orderByDesc('updated_at')->paginate(10);
         $pages = Page::orderByDesc('updated_at')->paginate(10);
+
         return view('admin.pages.home', compact('pages'));
         return view('admin.pages.home', compact('pages'));
     }
     }
 
 
@@ -275,30 +283,31 @@ trait AdminSettingsController
         ];
         ];
         switch (config('database.default')) {
         switch (config('database.default')) {
             case 'pgsql':
             case 'pgsql':
-            $exp = DB::raw('select version();');
-            $expQuery = $exp->getValue(DB::connection()->getQueryGrammar());
-            $sys['database'] = [
-                'name' => 'Postgres',
-                'version' => explode(' ', DB::select($expQuery)[0]->version)[1]
-            ];
-            break;
+                $exp = DB::raw('select version();');
+                $expQuery = $exp->getValue(DB::connection()->getQueryGrammar());
+                $sys['database'] = [
+                    'name' => 'Postgres',
+                    'version' => explode(' ', DB::select($expQuery)[0]->version)[1],
+                ];
+                break;
 
 
             case 'mysql':
             case 'mysql':
-            $exp = DB::raw('select version()');
-            $expQuery = $exp->getValue(DB::connection()->getQueryGrammar());
-            $sys['database'] = [
-                'name' => 'MySQL',
-                'version' => DB::select($expQuery)[0]->{'version()'}
-            ];
-            break;
+                $exp = DB::raw('select version()');
+                $expQuery = $exp->getValue(DB::connection()->getQueryGrammar());
+                $sys['database'] = [
+                    'name' => 'MySQL',
+                    'version' => DB::select($expQuery)[0]->{'version()'},
+                ];
+                break;
 
 
             default:
             default:
-            $sys['database'] = [
-                'name' => 'Unknown',
-                'version' => '?'
-            ];
-            break;
+                $sys['database'] = [
+                    'name' => 'Unknown',
+                    'version' => '?',
+                ];
+                break;
         }
         }
+
         return view('admin.settings.system', compact('sys'));
         return view('admin.settings.system', compact('sys'));
     }
     }
 }
 }

+ 3 - 0
app/Http/Controllers/ProfileMigrationController.php

@@ -23,6 +23,9 @@ class ProfileMigrationController extends Controller
     public function index(Request $request)
     public function index(Request $request)
     {
     {
         abort_if((bool) config_cache('federation.activitypub.enabled') === false, 404);
         abort_if((bool) config_cache('federation.activitypub.enabled') === false, 404);
+        if ((bool) config_cache('federation.migration') === false) {
+            return redirect(route('help.account-migration'));
+        }
         $hasExistingMigration = ProfileMigration::whereProfileId($request->user()->profile_id)
         $hasExistingMigration = ProfileMigration::whereProfileId($request->user()->profile_id)
             ->where('created_at', '>', now()->subDays(30))
             ->where('created_at', '>', now()->subDays(30))
             ->exists();
             ->exists();

+ 4 - 0
app/Http/Requests/ProfileMigrationStoreRequest.php

@@ -15,6 +15,10 @@ class ProfileMigrationStoreRequest extends FormRequest
      */
      */
     public function authorize(): bool
     public function authorize(): bool
     {
     {
+        if ((bool) config_cache('federation.activitypub.enabled') === false ||
+            (bool) config_cache('federation.migration') === false) {
+            return false;
+        }
         if (! $this->user() || $this->user()->status) {
         if (! $this->user() || $this->user()->status) {
             return false;
             return false;
         }
         }

+ 121 - 119
app/Services/ConfigCacheService.php

@@ -2,127 +2,129 @@
 
 
 namespace App\Services;
 namespace App\Services;
 
 
-use Cache;
-use Config;
 use App\Models\ConfigCache as ConfigCacheModel;
 use App\Models\ConfigCache as ConfigCacheModel;
+use Cache;
 
 
 class ConfigCacheService
 class ConfigCacheService
 {
 {
-	const CACHE_KEY = 'config_cache:_v0-key:';
-
-	public static function get($key)
-	{
-		$cacheKey = self::CACHE_KEY . $key;
-		$ttl = now()->addHours(12);
-		if(!config('instance.enable_cc')) {
-			return config($key);
-		}
-
-		return Cache::remember($cacheKey, $ttl, function() use($key) {
-
-			$allowed = [
-				'app.name',
-				'app.short_description',
-				'app.description',
-				'app.rules',
-
-				'pixelfed.max_photo_size',
-				'pixelfed.max_album_length',
-				'pixelfed.image_quality',
-				'pixelfed.media_types',
-
-				'pixelfed.open_registration',
-				'federation.activitypub.enabled',
-				'instance.stories.enabled',
-				'pixelfed.oauth_enabled',
-				'pixelfed.import.instagram.enabled',
-				'pixelfed.bouncer.enabled',
-
-				'pixelfed.enforce_email_verification',
-				'pixelfed.max_account_size',
-				'pixelfed.enforce_account_limit',
-
-				'uikit.custom.css',
-				'uikit.custom.js',
-				'uikit.show_custom.css',
-				'uikit.show_custom.js',
-				'about.title',
-
-				'pixelfed.cloud_storage',
-
-				'account.autofollow',
-				'account.autofollow_usernames',
-				'config.discover.features',
-
-				'instance.has_legal_notice',
-				'instance.avatar.local_to_cloud',
-
-				'pixelfed.directory',
-				'app.banner_image',
-				'pixelfed.directory.submission-key',
-				'pixelfed.directory.submission-ts',
-				'pixelfed.directory.has_submitted',
-				'pixelfed.directory.latest_response',
-				'pixelfed.directory.is_synced',
-				'pixelfed.directory.testimonials',
-
-				'instance.landing.show_directory',
-				'instance.landing.show_explore',
-				'instance.admin.pid',
-				'instance.banner.blurhash',
-
-				'autospam.nlp.enabled',
-
-				'instance.curated_registration.enabled',
-				// 'system.user_mode'
-			];
-
-			if(!config('instance.enable_cc')) {
-				return config($key);
-			}
-
-			if(!in_array($key, $allowed)) {
-				return config($key);
-			}
-
-			$v = config($key);
-			$c = ConfigCacheModel::where('k', $key)->first();
-
-			if($c) {
-				return $c->v ?? config($key);
-			}
-
-			if(!$v) {
-				return;
-			}
-
-			$cc = new ConfigCacheModel;
-			$cc->k = $key;
-			$cc->v = $v;
-			$cc->save();
-
-			return $v;
-		});
-	}
-
-	public static function put($key, $val)
-	{
-		$exists = ConfigCacheModel::whereK($key)->first();
-
-		if($exists) {
-			$exists->v = $val;
-			$exists->save();
-			Cache::put(self::CACHE_KEY . $key, $val, now()->addHours(12));
-			return self::get($key);
-		}
-
-		$cc = new ConfigCacheModel;
-		$cc->k = $key;
-		$cc->v = $val;
-		$cc->save();
-
-		Cache::put(self::CACHE_KEY . $key, $val, now()->addHours(12));
-
-		return self::get($key);
-	}
+    const CACHE_KEY = 'config_cache:_v0-key:';
+
+    public static function get($key)
+    {
+        $cacheKey = self::CACHE_KEY.$key;
+        $ttl = now()->addHours(12);
+        if (! config('instance.enable_cc')) {
+            return config($key);
+        }
+
+        return Cache::remember($cacheKey, $ttl, function () use ($key) {
+
+            $allowed = [
+                'app.name',
+                'app.short_description',
+                'app.description',
+                'app.rules',
+
+                'pixelfed.max_photo_size',
+                'pixelfed.max_album_length',
+                'pixelfed.image_quality',
+                'pixelfed.media_types',
+
+                'pixelfed.open_registration',
+                'federation.activitypub.enabled',
+                'instance.stories.enabled',
+                'pixelfed.oauth_enabled',
+                'pixelfed.import.instagram.enabled',
+                'pixelfed.bouncer.enabled',
+
+                'pixelfed.enforce_email_verification',
+                'pixelfed.max_account_size',
+                'pixelfed.enforce_account_limit',
+
+                'uikit.custom.css',
+                'uikit.custom.js',
+                'uikit.show_custom.css',
+                'uikit.show_custom.js',
+                'about.title',
+
+                'pixelfed.cloud_storage',
+
+                'account.autofollow',
+                'account.autofollow_usernames',
+                'config.discover.features',
+
+                'instance.has_legal_notice',
+                'instance.avatar.local_to_cloud',
+
+                'pixelfed.directory',
+                'app.banner_image',
+                'pixelfed.directory.submission-key',
+                'pixelfed.directory.submission-ts',
+                'pixelfed.directory.has_submitted',
+                'pixelfed.directory.latest_response',
+                'pixelfed.directory.is_synced',
+                'pixelfed.directory.testimonials',
+
+                'instance.landing.show_directory',
+                'instance.landing.show_explore',
+                'instance.admin.pid',
+                'instance.banner.blurhash',
+
+                'autospam.nlp.enabled',
+
+                'instance.curated_registration.enabled',
+
+                'federation.migration',
+                // 'system.user_mode'
+            ];
+
+            if (! config('instance.enable_cc')) {
+                return config($key);
+            }
+
+            if (! in_array($key, $allowed)) {
+                return config($key);
+            }
+
+            $v = config($key);
+            $c = ConfigCacheModel::where('k', $key)->first();
+
+            if ($c) {
+                return $c->v ?? config($key);
+            }
+
+            if (! $v) {
+                return;
+            }
+
+            $cc = new ConfigCacheModel;
+            $cc->k = $key;
+            $cc->v = $v;
+            $cc->save();
+
+            return $v;
+        });
+    }
+
+    public static function put($key, $val)
+    {
+        $exists = ConfigCacheModel::whereK($key)->first();
+
+        if ($exists) {
+            $exists->v = $val;
+            $exists->save();
+            Cache::put(self::CACHE_KEY.$key, $val, now()->addHours(12));
+
+            return self::get($key);
+        }
+
+        $cc = new ConfigCacheModel;
+        $cc->k = $key;
+        $cc->v = $val;
+        $cc->save();
+
+        Cache::put(self::CACHE_KEY.$key, $val, now()->addHours(12));
+
+        return self::get($key);
+    }
 }
 }

+ 2 - 0
config/federation.php

@@ -57,4 +57,6 @@ return [
         // max size in bytes, default is 2mb
         // max size in bytes, default is 2mb
         'max_size' => env('CUSTOM_EMOJI_MAX_SIZE', 2000000),
         'max_size' => env('CUSTOM_EMOJI_MAX_SIZE', 2000000),
     ],
     ],
+
+    'migration' => env('PF_ACCT_MIGRATION_ENABLED', true),
 ];
 ];

+ 10 - 0
resources/views/admin/settings/home.blade.php

@@ -103,6 +103,16 @@
 				</div>
 				</div>
 				<p class="mb-4 small">ActivityPub federation, compatible with Pixelfed, Mastodon and other projects.</p>
 				<p class="mb-4 small">ActivityPub federation, compatible with Pixelfed, Mastodon and other projects.</p>
 
 
+                <div class="custom-control custom-checkbox mt-2">
+                    <input type="checkbox" name="account_migration" class="custom-control-input" id="ap_mig" {{(bool)config_cache('federation.migration') ? 'checked' : ''}} {{(bool) config_cache('federation.activitypub.enabled') ? '' : 'disabled="disabled"'}}>
+                    <label class="custom-control-label font-weight-bold" for="ap_mig">Account Migration</label>
+                </div>
+                @if((bool) config_cache('federation.activitypub.enabled'))
+                <p class="mb-4 small">Allow local accounts to migrate to other local or remote accounts.</p>
+                @else
+                <p class="mb-4 small text-muted"><strong>ActivityPub Required</strong> Allow local accounts to migrate to other local or remote accounts.</p>
+                @endif
+
 				{{-- <div class="custom-control custom-checkbox mt-2">
 				{{-- <div class="custom-control custom-checkbox mt-2">
 					<input type="checkbox" name="open_registration" class="custom-control-input" id="openReg" {{config_cache('pixelfed.open_registration') ? 'checked' : ''}}>
 					<input type="checkbox" name="open_registration" class="custom-control-input" id="openReg" {{config_cache('pixelfed.open_registration') ? 'checked' : ''}}>
 					<label class="custom-control-label font-weight-bold" for="openReg">Open Registrations</label>
 					<label class="custom-control-label font-weight-bold" for="openReg">Open Registrations</label>

+ 4 - 0
resources/views/settings/home.blade.php

@@ -88,6 +88,7 @@
 			</div>
 			</div>
 		</div>
 		</div>
 
 
+        @if((bool) config_cache('federation.activitypub.enabled'))
         <div class="form-group row">
         <div class="form-group row">
             <label for="aliases" class="col-sm-3 col-form-label font-weight-bold">Account Aliases</label>
             <label for="aliases" class="col-sm-3 col-form-label font-weight-bold">Account Aliases</label>
             <div class="col-sm-9" id="aliases">
             <div class="col-sm-9" id="aliases">
@@ -96,6 +97,7 @@
             </div>
             </div>
         </div>
         </div>
 
 
+        @if((bool) config_cache('federation.migration'))
         <div class="form-group row">
         <div class="form-group row">
             <label for="aliases" class="col-sm-3 col-form-label font-weight-bold">Account Migrate</label>
             <label for="aliases" class="col-sm-3 col-form-label font-weight-bold">Account Migrate</label>
             <div class="col-sm-9" id="aliases">
             <div class="col-sm-9" id="aliases">
@@ -103,6 +105,8 @@
                 <p class="help-text text-muted small">To redirect this account to a different one (where supported).</p>
                 <p class="help-text text-muted small">To redirect this account to a different one (where supported).</p>
             </div>
             </div>
         </div>
         </div>
+        @endif
+        @endif
 		@if(config_cache('pixelfed.enforce_account_limit'))
 		@if(config_cache('pixelfed.enforce_account_limit'))
 		<div class="pt-3">
 		<div class="pt-3">
 			<p class="font-weight-bold text-muted text-center">Storage Usage</p>
 			<p class="font-weight-bold text-muted text-center">Storage Usage</p>

+ 2 - 1
resources/views/settings/migration/index.blade.php

@@ -40,7 +40,8 @@
                 @if($hasExistingMigration)
                 @if($hasExistingMigration)
                 <div class="row">
                 <div class="row">
                     <div class="col-12 mt-5">
                     <div class="col-12 mt-5">
-                        <p class="lead mb-0 text-center">You have migrated your account already.</p>
+                        <p class="lead text-center">You have migrated your account already.</p>
+                        <p>You can only migrate your account once per 30 days. If you want to migrate your followers back to this account, follow this process in reverse.</p>
                     </div>
                     </div>
                 </div>
                 </div>
                 @else
                 @else

+ 19 - 0
resources/views/site/help/account-migration.blade.php

@@ -0,0 +1,19 @@
+@extends('site.help.partial.template', ['breadcrumb'=>'Account Migration'])
+
+@section('section')
+
+    <div class="title">
+        <h3 class="font-weight-bold">Account Migration</h3>
+    </div>
+
+    <hr>
+
+    @if((bool) config_cache('federation.migration') === false)
+    <div class="alert alert-danger">
+        <p class="font-weight-bold mb-0">Account Migration is not available on this server.</p>
+    </div>
+    @endif
+
+    <p class="lead">Account Migration is a feature that allows users to move their account followers from one Pixelfed instance (server) to another.</p>
+    <p class="lead">This can be useful if a user wants to switch to a different instance due to preferences for its community, policies, or features.</p>
+@endsection

+ 1 - 0
routes/web.php

@@ -314,6 +314,7 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
             Route::view('parental-controls', 'site.help.parental-controls');
             Route::view('parental-controls', 'site.help.parental-controls');
             Route::view('email-confirmation-issues', 'site.help.email-confirmation-issues')->name('help.email-confirmation-issues');
             Route::view('email-confirmation-issues', 'site.help.email-confirmation-issues')->name('help.email-confirmation-issues');
             Route::view('curated-onboarding', 'site.help.curated-onboarding')->name('help.curated-onboarding');
             Route::view('curated-onboarding', 'site.help.curated-onboarding')->name('help.curated-onboarding');
+            Route::view('account-migration', 'site.help.account-migration')->name('help.account-migration');
         });
         });
         Route::get('newsroom/{year}/{month}/{slug}', 'NewsroomController@show');
         Route::get('newsroom/{year}/{month}/{slug}', 'NewsroomController@show');
         Route::get('newsroom/archive', 'NewsroomController@archive');
         Route::get('newsroom/archive', 'NewsroomController@archive');