Browse Source

Add disable_embeds setting, and fix cache invalidation in other settings

Daniel Supernault 1 year ago
parent
commit
c5e7e91777

+ 2 - 13
app/Http/Controllers/Api/ApiV1Controller.php

@@ -194,19 +194,7 @@ class ApiV1Controller extends Controller
         ];
 
         if ($request->has(self::PF_API_ENTITY_KEY)) {
-            $settings = $user->settings;
-            $other = array_merge(AccountService::defaultSettings()['other'], $settings->other ?? []);
-            $res['settings'] = [
-                'reduce_motion' => (bool) $settings->reduce_motion,
-                'high_contrast_mode' => (bool) $settings->high_contrast_mode,
-                'video_autoplay' => (bool) $settings->video_autoplay,
-                'media_descriptions' => (bool) $settings->media_descriptions,
-                'crawlable' => (bool) $settings->crawlable,
-                'show_profile_follower_count' => (bool) $settings->show_profile_follower_count,
-                'show_profile_following_count' => (bool) $settings->show_profile_following_count,
-                'public_dm' => (bool) $settings->public_dm,
-                'disable_embeds' => (bool) $other['disable_embeds'],
-            ];
+            $res['settings'] = AccountService::getAccountSettings($user->profile_id);
         }
 
         return $this->json($res);
@@ -466,6 +454,7 @@ class ApiV1Controller extends Controller
             Cache::forget('pf:acct-trans:hideFollowing:'.$profile->id);
             Cache::forget('pf:acct-trans:hideFollowers:'.$profile->id);
             AccountService::del($user->profile_id);
+            AccountService::forgetAccountSettings($profile->id);
         }
 
         if ($syncLicenses && $licenseChanged) {

+ 1 - 1
app/Http/Controllers/ProfileController.php

@@ -361,7 +361,7 @@ class ProfileController extends Controller
             return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
         }
 
-        if (AccountService::canEmbed($profile->user_id) == false) {
+        if (AccountService::canEmbed($profile->id) == false) {
             return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
         }
 

+ 21 - 22
app/Http/Controllers/Settings/HomeSettings.php

@@ -4,21 +4,17 @@ namespace App\Http\Controllers\Settings;
 
 use App\AccountLog;
 use App\EmailVerification;
+use App\Mail\PasswordChange;
 use App\Media;
-use App\Profile;
-use App\User;
-use App\UserFilter;
+use App\Services\AccountService;
+use App\Services\PronounService;
 use App\Util\Lexer\Autolink;
 use App\Util\Lexer\PrettyNumber;
 use Auth;
 use Cache;
-use DB;
+use Illuminate\Http\Request;
 use Mail;
 use Purify;
-use App\Mail\PasswordChange;
-use Illuminate\Http\Request;
-use App\Services\AccountService;
-use App\Services\PronounService;
 
 trait HomeSettings
 {
@@ -40,11 +36,11 @@ trait HomeSettings
     public function homeUpdate(Request $request)
     {
         $this->validate($request, [
-            'name'    => 'nullable|string|max:'.config('pixelfed.max_name_length'),
-            'bio'     => 'nullable|string|max:'.config('pixelfed.max_bio_length'),
+            'name' => 'nullable|string|max:'.config('pixelfed.max_name_length'),
+            'bio' => 'nullable|string|max:'.config('pixelfed.max_bio_length'),
             'website' => 'nullable|url',
             'language' => 'nullable|string|min:2|max:5',
-            'pronouns' => 'nullable|array|max:4'
+            'pronouns' => 'nullable|array|max:4',
         ]);
 
         $changes = false;
@@ -57,14 +53,14 @@ trait HomeSettings
         $pronouns = $request->input('pronouns');
         $existingPronouns = PronounService::get($profile->id);
         $layout = $request->input('profile_layout');
-        if($layout) {
-            $layout = !in_array($layout, ['metro', 'moment']) ? 'metro' : $layout;
+        if ($layout) {
+            $layout = ! in_array($layout, ['metro', 'moment']) ? 'metro' : $layout;
         }
 
         $enforceEmailVerification = config_cache('pixelfed.enforce_email_verification');
 
         // Only allow email to be updated if not yet verified
-        if (!$enforceEmailVerification || !$changes && $user->email_verified_at) {
+        if (! $enforceEmailVerification || ! $changes && $user->email_verified_at) {
             if ($profile->name != $name) {
                 $changes = true;
                 $user->name = $name;
@@ -81,7 +77,7 @@ trait HomeSettings
                 $profile->bio = Autolink::create()->autolink($bio);
             }
 
-            if($user->language != $language &&
+            if ($user->language != $language &&
                 in_array($language, \App\Util\Localization\Localization::languages())
             ) {
                 $changes = true;
@@ -89,8 +85,8 @@ trait HomeSettings
                 session()->put('locale', $language);
             }
 
-            if($existingPronouns != $pronouns) {
-                if($pronouns && in_array('Select Pronoun(s)', $pronouns)) {
+            if ($existingPronouns != $pronouns) {
+                if ($pronouns && in_array('Select Pronoun(s)', $pronouns)) {
                     PronounService::clear($profile->id);
                 } else {
                     PronounService::put($profile->id, $pronouns);
@@ -102,7 +98,9 @@ trait HomeSettings
             $user->save();
             $profile->save();
             Cache::forget('user:account:id:'.$user->id);
+            AccountService::forgetAccountSettings($profile->id);
             AccountService::del($profile->id);
+
             return redirect('/settings/home')->with('status', 'Profile successfully updated!');
         }
 
@@ -117,10 +115,10 @@ trait HomeSettings
     public function passwordUpdate(Request $request)
     {
         $this->validate($request, [
-        'current'                => 'required|string',
-        'password'               => 'required|string',
-        'password_confirmation'  => 'required|string',
-      ]);
+            'current' => 'required|string',
+            'password' => 'required|string',
+            'password_confirmation' => 'required|string',
+        ]);
 
         $current = $request->input('current');
         $new = $request->input('password');
@@ -144,6 +142,7 @@ trait HomeSettings
             $log->save();
 
             Mail::to($request->user())->send(new PasswordChange($user));
+
             return redirect('/settings/home')->with('status', 'Password successfully updated!');
         } else {
             return redirect()->back()->with('error', 'There was an error with your request! Please try again.');
@@ -159,7 +158,7 @@ trait HomeSettings
     public function emailUpdate(Request $request)
     {
         $this->validate($request, [
-            'email'   => 'required|email|unique:users,email',
+            'email' => 'required|email|unique:users,email',
         ]);
         $changes = false;
         $email = $request->input('email');

+ 19 - 0
app/Http/Controllers/Settings/PrivacySettings.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Settings;
 
 use App\Follower;
 use App\Profile;
+use App\Services\AccountService;
 use App\Services\RelationshipService;
 use App\UserFilter;
 use Auth;
@@ -19,7 +20,13 @@ trait PrivacySettings
         $settings = $user->settings;
         $profile = $user->profile;
         $is_private = $profile->is_private;
+        $cachedSettings = AccountService::getAccountSettings($profile->id);
         $settings['is_private'] = (bool) $is_private;
+        if ($cachedSettings && isset($cachedSettings['disable_embeds'])) {
+            $settings['disable_embeds'] = (bool) $cachedSettings['disable_embeds'];
+        } else {
+            $settings['disable_embeds'] = false;
+        }
 
         return view('settings.privacy', compact('settings', 'profile'));
     }
@@ -28,6 +35,7 @@ trait PrivacySettings
     {
         $settings = $request->user()->settings;
         $profile = $request->user()->profile;
+        $other = $settings->other;
         $fields = [
             'is_private',
             'crawlable',
@@ -42,6 +50,16 @@ trait PrivacySettings
         $profile->is_suggestable = $request->input('is_suggestable') == 'on';
         $profile->save();
 
+        if ($request->has('disable_embeds')) {
+            $other['disable_embeds'] = true;
+            $settings->other = $other;
+            $settings->save();
+        } else {
+            $other['disable_embeds'] = false;
+            $settings->other = $other;
+            $settings->save();
+        }
+
         foreach ($fields as $field) {
             $form = $request->input($field);
             if ($field == 'is_private') {
@@ -91,6 +109,7 @@ trait PrivacySettings
         Cache::forget('pf:acct-trans:hideFollowers:'.$pid);
         Cache::forget('pfc:cached-user:wt:'.strtolower($profile->username));
         Cache::forget('pfc:cached-user:wot:'.strtolower($profile->username));
+        AccountService::forgetAccountSettings($profile->id);
 
         return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
     }

+ 312 - 305
app/Http/Controllers/SettingsController.php

@@ -2,270 +2,275 @@
 
 namespace App\Http\Controllers;
 
-use App\AccountLog;
-use App\Following;
+use App\Http\Controllers\Settings\ExportSettings;
+use App\Http\Controllers\Settings\HomeSettings;
+use App\Http\Controllers\Settings\LabsSettings;
+use App\Http\Controllers\Settings\PrivacySettings;
+use App\Http\Controllers\Settings\RelationshipSettings;
+use App\Http\Controllers\Settings\SecuritySettings;
+use App\Jobs\DeletePipeline\DeleteAccountPipeline;
+use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
 use App\ProfileSponsor;
-use App\Report;
-use App\UserFilter;
+use App\Services\AccountService;
 use App\UserSetting;
-use Auth, Cookie, DB, Cache, Purify;
-use Illuminate\Support\Facades\Redis;
+use Auth;
+use Cache;
 use Carbon\Carbon;
+use Cookie;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Str;
-use App\Http\Controllers\Settings\{
-	ExportSettings,
-	LabsSettings,
-	HomeSettings,
-	PrivacySettings,
-	RelationshipSettings,
-	SecuritySettings
-};
-use App\Jobs\DeletePipeline\DeleteAccountPipeline;
-use App\Jobs\MediaPipeline\MediaSyncLicensePipeline;
-use App\Services\AccountService;
 
 class SettingsController extends Controller
 {
-	use ExportSettings,
-	LabsSettings,
-	HomeSettings,
-	PrivacySettings,
-	RelationshipSettings,
-	SecuritySettings;
-
-	public function __construct()
-	{
-		$this->middleware('auth');
-	}
-
-	public function accessibility()
-	{
-		$settings = Auth::user()->settings;
-
-		return view('settings.accessibility', compact('settings'));
-	}
-
-	public function accessibilityStore(Request $request)
-	{
-		$settings = Auth::user()->settings;
-		$fields = [
-		  'compose_media_descriptions',
-		  'reduce_motion',
-		  'optimize_screen_reader',
-		  'high_contrast_mode',
-		  'video_autoplay',
-		];
-		foreach ($fields as $field) {
-			$form = $request->input($field);
-			if ($form == 'on') {
-				$settings->{$field} = true;
-			} else {
-				$settings->{$field} = false;
-			}
-			$settings->save();
-		}
-
-		return redirect(route('settings.accessibility'))->with('status', 'Settings successfully updated!');
-	}
-
-	public function notifications()
-	{
-		return view('settings.notifications');
-	}
-
-	public function applications()
-	{
-		return view('settings.applications');
-	}
-
-	public function dataImport()
-	{
-		return view('settings.import.home');
-	}
-
-	public function dataImportInstagram()
-	{
-		abort(404);
-	}
-
-	public function developers()
-	{
-		return view('settings.developers');
-	}
-
-	public function removeAccountTemporary(Request $request)
-	{
-		$user = Auth::user();
-		abort_if(!config('pixelfed.account_deletion'), 403);
-		abort_if($user->is_admin, 403);
-
-		return view('settings.remove.temporary');
-	}
-
-	public function removeAccountTemporarySubmit(Request $request)
-	{
-		$user = Auth::user();
-		abort_if(!config('pixelfed.account_deletion'), 403);
-		abort_if($user->is_admin, 403);
-		$profile = $user->profile;
-		$user->status = 'disabled';
-		$profile->status = 'disabled';
-		$user->save();
-		$profile->save();
-		Auth::logout();
-		Cache::forget('profiles:private');
-		return redirect('/');
-	}
-
-	public function removeAccountPermanent(Request $request)
-	{
-		$user = Auth::user();
-		abort_if($user->is_admin, 403);
-		return view('settings.remove.permanent');
-	}
-
-	public function removeAccountPermanentSubmit(Request $request)
-	{
-		if(config('pixelfed.account_deletion') == false) {
-			abort(404);
-		}
-		$user = Auth::user();
-		abort_if(!config('pixelfed.account_deletion'), 403);
-		abort_if($user->is_admin, 403);
-		$profile = $user->profile;
-		$ts = Carbon::now()->addMonth();
-		$user->email = $user->id;
-		$user->password = '';
-		$user->status = 'delete';
-		$profile->status = 'delete';
-		$user->delete_after = $ts;
-		$profile->delete_after = $ts;
-		$user->save();
-		$profile->save();
-		Cache::forget('profiles:private');
-		AccountService::del($profile->id);
-		Auth::logout();
-		DeleteAccountPipeline::dispatch($user)->onQueue('low');
-		return redirect('/');
-	}
-
-	public function requestFullExport(Request $request)
-	{
-		$user = Auth::user();
-		return view('settings.export.show');
-	}
-
-	public function metroDarkMode(Request $request)
-	{
-		$this->validate($request, [
-			'mode' => 'required|string|in:light,dark'
-		]);
-
-		$mode = $request->input('mode');
-
-		if($mode == 'dark') {
-			$cookie = Cookie::make('dark-mode', 'true', 43800);
-		} else {
-			$cookie = Cookie::forget('dark-mode');
-		}
-
-		return response()->json([200])->cookie($cookie);
-	}
-
-	public function sponsor()
-	{
-		$default = [
-			'patreon' => null,
-			'liberapay' => null,
-			'opencollective' => null
-		];
-		$sponsors = ProfileSponsor::whereProfileId(Auth::user()->profile->id)->first();
-		$sponsors = $sponsors ? json_decode($sponsors->sponsors, true) : $default;
-		return view('settings.sponsor', compact('sponsors'));
-	}
-
-	public function sponsorStore(Request $request)
-	{
-		$this->validate($request, [
-			'patreon' => 'nullable|string',
-			'liberapay' => 'nullable|string',
-			'opencollective' => 'nullable|string'
-		]);
-
-		$patreon = Str::startsWith($request->input('patreon'), 'https://') ?
-			substr($request->input('patreon'), 8) :
-			$request->input('patreon');
-
-		$liberapay = Str::startsWith($request->input('liberapay'), 'https://') ?
-			substr($request->input('liberapay'), 8) :
-			$request->input('liberapay');
-
-		$opencollective = Str::startsWith($request->input('opencollective'), 'https://') ?
-			substr($request->input('opencollective'), 8) :
-			$request->input('opencollective');
-
-		$patreon = Str::startsWith($patreon, 'patreon.com/') ? e($patreon) : null;
-		$liberapay = Str::startsWith($liberapay, 'liberapay.com/') ? e($liberapay) : null;
-		$opencollective = Str::startsWith($opencollective, 'opencollective.com/') ? e($opencollective) : null;
-
-		if(empty($patreon) && empty($liberapay) && empty($opencollective)) {
-			return redirect(route('settings'))->with('error', 'An error occured. Please try again later.');
-		}
-
-		$res = [
-			'patreon' => $patreon,
-			'liberapay' => $liberapay,
-			'opencollective' => $opencollective
-		];
-
-		$sponsors = ProfileSponsor::firstOrCreate([
-			'profile_id' => Auth::user()->profile_id ?? Auth::user()->profile->id
-		]);
-		$sponsors->sponsors = json_encode($res);
-		$sponsors->save();
-		$sponsors = $res;
-		return redirect(route('settings'))->with('status', 'Sponsor settings successfully updated!');
-	}
-
-	public function timelineSettings(Request $request)
-	{
+    use ExportSettings,
+        HomeSettings,
+        LabsSettings,
+        PrivacySettings,
+        RelationshipSettings,
+        SecuritySettings;
+
+    public function __construct()
+    {
+        $this->middleware('auth');
+    }
+
+    public function accessibility()
+    {
+        $settings = Auth::user()->settings;
+
+        return view('settings.accessibility', compact('settings'));
+    }
+
+    public function accessibilityStore(Request $request)
+    {
+        $user = $request->user();
+        $settings = $user->settings;
+        $fields = [
+            'compose_media_descriptions',
+            'reduce_motion',
+            'optimize_screen_reader',
+            'high_contrast_mode',
+            'video_autoplay',
+        ];
+        foreach ($fields as $field) {
+            $form = $request->input($field);
+            if ($form == 'on') {
+                $settings->{$field} = true;
+            } else {
+                $settings->{$field} = false;
+            }
+            $settings->save();
+        }
+        AccountService::forgetAccountSettings($user->profile_id);
+
+        return redirect(route('settings.accessibility'))->with('status', 'Settings successfully updated!');
+    }
+
+    public function notifications()
+    {
+        return view('settings.notifications');
+    }
+
+    public function applications()
+    {
+        return view('settings.applications');
+    }
+
+    public function dataImport()
+    {
+        return view('settings.import.home');
+    }
+
+    public function dataImportInstagram()
+    {
+        abort(404);
+    }
+
+    public function developers()
+    {
+        return view('settings.developers');
+    }
+
+    public function removeAccountTemporary(Request $request)
+    {
+        $user = Auth::user();
+        abort_if(! config('pixelfed.account_deletion'), 403);
+        abort_if($user->is_admin, 403);
+
+        return view('settings.remove.temporary');
+    }
+
+    public function removeAccountTemporarySubmit(Request $request)
+    {
+        $user = Auth::user();
+        abort_if(! config('pixelfed.account_deletion'), 403);
+        abort_if($user->is_admin, 403);
+        $profile = $user->profile;
+        $user->status = 'disabled';
+        $profile->status = 'disabled';
+        $user->save();
+        $profile->save();
+        Auth::logout();
+        Cache::forget('profiles:private');
+
+        return redirect('/');
+    }
+
+    public function removeAccountPermanent(Request $request)
+    {
+        $user = Auth::user();
+        abort_if($user->is_admin, 403);
+
+        return view('settings.remove.permanent');
+    }
+
+    public function removeAccountPermanentSubmit(Request $request)
+    {
+        if (config('pixelfed.account_deletion') == false) {
+            abort(404);
+        }
+        $user = Auth::user();
+        abort_if(! config('pixelfed.account_deletion'), 403);
+        abort_if($user->is_admin, 403);
+        $profile = $user->profile;
+        $ts = Carbon::now()->addMonth();
+        $user->email = $user->id;
+        $user->password = '';
+        $user->status = 'delete';
+        $profile->status = 'delete';
+        $user->delete_after = $ts;
+        $profile->delete_after = $ts;
+        $user->save();
+        $profile->save();
+        Cache::forget('profiles:private');
+        AccountService::del($profile->id);
+        Auth::logout();
+        DeleteAccountPipeline::dispatch($user)->onQueue('low');
+
+        return redirect('/');
+    }
+
+    public function requestFullExport(Request $request)
+    {
+        $user = Auth::user();
+
+        return view('settings.export.show');
+    }
+
+    public function metroDarkMode(Request $request)
+    {
+        $this->validate($request, [
+            'mode' => 'required|string|in:light,dark',
+        ]);
+
+        $mode = $request->input('mode');
+
+        if ($mode == 'dark') {
+            $cookie = Cookie::make('dark-mode', 'true', 43800);
+        } else {
+            $cookie = Cookie::forget('dark-mode');
+        }
+
+        return response()->json([200])->cookie($cookie);
+    }
+
+    public function sponsor()
+    {
+        $default = [
+            'patreon' => null,
+            'liberapay' => null,
+            'opencollective' => null,
+        ];
+        $sponsors = ProfileSponsor::whereProfileId(Auth::user()->profile->id)->first();
+        $sponsors = $sponsors ? json_decode($sponsors->sponsors, true) : $default;
+
+        return view('settings.sponsor', compact('sponsors'));
+    }
+
+    public function sponsorStore(Request $request)
+    {
+        $this->validate($request, [
+            'patreon' => 'nullable|string',
+            'liberapay' => 'nullable|string',
+            'opencollective' => 'nullable|string',
+        ]);
+
+        $patreon = Str::startsWith($request->input('patreon'), 'https://') ?
+            substr($request->input('patreon'), 8) :
+            $request->input('patreon');
+
+        $liberapay = Str::startsWith($request->input('liberapay'), 'https://') ?
+            substr($request->input('liberapay'), 8) :
+            $request->input('liberapay');
+
+        $opencollective = Str::startsWith($request->input('opencollective'), 'https://') ?
+            substr($request->input('opencollective'), 8) :
+            $request->input('opencollective');
+
+        $patreon = Str::startsWith($patreon, 'patreon.com/') ? e($patreon) : null;
+        $liberapay = Str::startsWith($liberapay, 'liberapay.com/') ? e($liberapay) : null;
+        $opencollective = Str::startsWith($opencollective, 'opencollective.com/') ? e($opencollective) : null;
+
+        if (empty($patreon) && empty($liberapay) && empty($opencollective)) {
+            return redirect(route('settings'))->with('error', 'An error occured. Please try again later.');
+        }
+
+        $res = [
+            'patreon' => $patreon,
+            'liberapay' => $liberapay,
+            'opencollective' => $opencollective,
+        ];
+
+        $sponsors = ProfileSponsor::firstOrCreate([
+            'profile_id' => Auth::user()->profile_id ?? Auth::user()->profile->id,
+        ]);
+        $sponsors->sponsors = json_encode($res);
+        $sponsors->save();
+        $sponsors = $res;
+
+        return redirect(route('settings'))->with('status', 'Sponsor settings successfully updated!');
+    }
+
+    public function timelineSettings(Request $request)
+    {
         $uid = $request->user()->id;
-		$pid = $request->user()->profile_id;
-		$top = Redis::zscore('pf:tl:top', $pid) != false;
-		$replies = Redis::zscore('pf:tl:replies', $pid) != false;
+        $pid = $request->user()->profile_id;
+        $top = Redis::zscore('pf:tl:top', $pid) != false;
+        $replies = Redis::zscore('pf:tl:replies', $pid) != false;
         $userSettings = UserSetting::firstOrCreate([
-            'user_id' => $uid
+            'user_id' => $uid,
         ]);
-        if(!$userSettings || !$userSettings->other) {
+        if (! $userSettings || ! $userSettings->other) {
             $userSettings = [
                 'enable_reblogs' => false,
-                'photo_reblogs_only' => false
+                'photo_reblogs_only' => false,
             ];
         } else {
             $userSettings = array_merge([
                 'enable_reblogs' => false,
-                'photo_reblogs_only' => false
+                'photo_reblogs_only' => false,
             ],
-            $userSettings->other);
+                $userSettings->other);
         }
-		return view('settings.timeline', compact('top', 'replies', 'userSettings'));
-	}
 
-	public function updateTimelineSettings(Request $request)
-	{
+        return view('settings.timeline', compact('top', 'replies', 'userSettings'));
+    }
+
+    public function updateTimelineSettings(Request $request)
+    {
         $pid = $request->user()->profile_id;
-		$uid = $request->user()->id;
+        $uid = $request->user()->id;
         $this->validate($request, [
             'enable_reblogs' => 'sometimes',
-            'photo_reblogs_only' => 'sometimes'
+            'photo_reblogs_only' => 'sometimes',
         ]);
-		Redis::zrem('pf:tl:top', $pid);
-		Redis::zrem('pf:tl:replies', $pid);
+        Redis::zrem('pf:tl:top', $pid);
+        Redis::zrem('pf:tl:replies', $pid);
         $userSettings = UserSetting::firstOrCreate([
-            'user_id' => $uid
+            'user_id' => $uid,
         ]);
-		if($userSettings->other) {
+        if ($userSettings->other) {
             $other = $userSettings->other;
             $other['enable_reblogs'] = $request->has('enable_reblogs');
             $other['photo_reblogs_only'] = $request->has('photo_reblogs_only');
@@ -275,72 +280,74 @@ class SettingsController extends Controller
         }
         $userSettings->other = $other;
         $userSettings->save();
-		return redirect(route('settings'))->with('status', 'Timeline settings successfully updated!');
-	}
-
-	public function mediaSettings(Request $request)
-	{
-		$setting = UserSetting::whereUserId($request->user()->id)->firstOrFail();
-		$compose = $setting->compose_settings ? (
-			is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings
-			) : [
-			'default_license' => null,
-			'media_descriptions' => false
-		];
-		return view('settings.media', compact('compose'));
-	}
-
-	public function updateMediaSettings(Request $request)
-	{
-		$this->validate($request, [
-			'default' => 'required|int|min:1|max:16',
-			'sync' => 'nullable',
-			'media_descriptions' => 'nullable'
-		]);
-
-		$license = $request->input('default');
-		$sync = $request->input('sync') == 'on';
-		$media_descriptions = $request->input('media_descriptions') == 'on';
-		$uid = $request->user()->id;
-
-		$setting = UserSetting::whereUserId($uid)->firstOrFail();
-		$compose = is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings;
-		$changed = false;
-
-		if($sync) {
-			$key = 'pf:settings:mls_recently:'.$uid;
-			if(Cache::get($key) == 2) {
-				$msg = 'You can only sync licenses twice per 24 hours. Try again later.';
-				return redirect(route('settings'))
-					->with('error', $msg);
-			}
-		}
-
-		if(!isset($compose['default_license']) || $compose['default_license'] !== $license) {
-			$compose['default_license'] = (int) $license;
-			$changed = true;
-		}
-
-		if(!isset($compose['media_descriptions']) || $compose['media_descriptions'] !== $media_descriptions) {
-			$compose['media_descriptions'] = $media_descriptions;
-			$changed = true;
-		}
-
-		if($changed) {
-			$setting->compose_settings = $compose;
-			$setting->save();
-			Cache::forget('profile:compose:settings:' . $request->user()->id);
-		}
-
-		if($sync) {
-			$val = Cache::has($key) ? 2 : 1;
-			Cache::put($key, $val, 86400);
-			MediaSyncLicensePipeline::dispatch($uid, $license);
-			return redirect(route('settings'))->with('status', 'Media licenses successfully synced! It may take a few minutes to take effect for every post.');
-		}
-
-		return redirect(route('settings'))->with('status', 'Media settings successfully updated!');
-	}
 
-}
+        return redirect(route('settings'))->with('status', 'Timeline settings successfully updated!');
+    }
+
+    public function mediaSettings(Request $request)
+    {
+        $setting = UserSetting::whereUserId($request->user()->id)->firstOrFail();
+        $compose = $setting->compose_settings ? (
+            is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings
+        ) : [
+            'default_license' => null,
+            'media_descriptions' => false,
+        ];
+
+        return view('settings.media', compact('compose'));
+    }
+
+    public function updateMediaSettings(Request $request)
+    {
+        $this->validate($request, [
+            'default' => 'required|int|min:1|max:16',
+            'sync' => 'nullable',
+            'media_descriptions' => 'nullable',
+        ]);
+
+        $license = $request->input('default');
+        $sync = $request->input('sync') == 'on';
+        $media_descriptions = $request->input('media_descriptions') == 'on';
+        $uid = $request->user()->id;
 
+        $setting = UserSetting::whereUserId($uid)->firstOrFail();
+        $compose = is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings;
+        $changed = false;
+
+        if ($sync) {
+            $key = 'pf:settings:mls_recently:'.$uid;
+            if (Cache::get($key) == 2) {
+                $msg = 'You can only sync licenses twice per 24 hours. Try again later.';
+
+                return redirect(route('settings'))
+                    ->with('error', $msg);
+            }
+        }
+
+        if (! isset($compose['default_license']) || $compose['default_license'] !== $license) {
+            $compose['default_license'] = (int) $license;
+            $changed = true;
+        }
+
+        if (! isset($compose['media_descriptions']) || $compose['media_descriptions'] !== $media_descriptions) {
+            $compose['media_descriptions'] = $media_descriptions;
+            $changed = true;
+        }
+
+        if ($changed) {
+            $setting->compose_settings = $compose;
+            $setting->save();
+            Cache::forget('profile:compose:settings:'.$request->user()->id);
+        }
+
+        if ($sync) {
+            $val = Cache::has($key) ? 2 : 1;
+            Cache::put($key, $val, 86400);
+            MediaSyncLicensePipeline::dispatch($uid, $license);
+
+            return redirect(route('settings'))->with('status', 'Media licenses successfully synced! It may take a few minutes to take effect for every post.');
+        }
+
+        return redirect(route('settings'))->with('status', 'Media settings successfully updated!');
+    }
+}

+ 8 - 0
app/Http/Controllers/StatusController.php

@@ -135,6 +135,14 @@ class StatusController extends Controller
             return response($content)->header('X-Frame-Options', 'ALLOWALL');
         }
 
+        $embedCheck = AccountService::canEmbed($profile['id']);
+
+        if (! $embedCheck) {
+            $content = view('status.embed-removed');
+
+            return response($content)->header('X-Frame-Options', 'ALLOWALL');
+        }
+
         $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 3600, function () use ($profile) {
             $user = Profile::find($profile['id']);
             if (! $user) {

+ 131 - 69
app/Services/AccountService.php

@@ -2,50 +2,54 @@
 
 namespace App\Services;
 
-use Cache;
+use App\Models\UserDomainBlock;
 use App\Profile;
 use App\Status;
+use App\Transformer\Api\AccountTransformer;
 use App\User;
 use App\UserSetting;
-use App\Models\UserDomainBlock;
-use App\Transformer\Api\AccountTransformer;
-use League\Fractal;
-use League\Fractal\Serializer\ArraySerializer;
+use Cache;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Str;
-use \NumberFormatter;
+use League\Fractal;
+use League\Fractal\Serializer\ArraySerializer;
+use NumberFormatter;
 
 class AccountService
 {
     const CACHE_KEY = 'pf:services:account:';
 
+    const CACHE_PF_ACCT_SETTINGS_KEY = 'pf:services:account-settings:';
+
     public static function get($id, $softFail = false)
     {
-        $res = Cache::remember(self::CACHE_KEY . $id, 43200, function() use($id) {
+        $res = Cache::remember(self::CACHE_KEY.$id, 43200, function () use ($id) {
             $fractal = new Fractal\Manager();
             $fractal->setSerializer(new ArraySerializer());
             $profile = Profile::find($id);
-            if(!$profile || $profile->status === 'delete') {
+            if (! $profile || $profile->status === 'delete') {
                 return null;
             }
             $resource = new Fractal\Resource\Item($profile, new AccountTransformer());
+
             return $fractal->createData($resource)->toArray();
         });
 
-        if(!$res) {
+        if (! $res) {
             return $softFail ? null : abort(404);
         }
+
         return $res;
     }
 
     public static function getMastodon($id, $softFail = false)
     {
         $account = self::get($id, $softFail);
-        if(!$account) {
+        if (! $account) {
             return null;
         }
 
-        if(config('exp.emc') == false) {
+        if (config('exp.emc') == false) {
             return $account;
         }
 
@@ -73,41 +77,86 @@ class AccountService
 
     public static function del($id)
     {
-        Cache::forget('pf:activitypub:user-object:by-id:' . $id);
-        return Cache::forget(self::CACHE_KEY . $id);
+        Cache::forget('pf:activitypub:user-object:by-id:'.$id);
+
+        return Cache::forget(self::CACHE_KEY.$id);
     }
 
     public static function settings($id)
     {
-        return Cache::remember('profile:compose:settings:' . $id, 604800, function() use($id) {
+        return Cache::remember('profile:compose:settings:'.$id, 604800, function () use ($id) {
             $settings = UserSetting::whereUserId($id)->first();
-            if(!$settings) {
+            if (! $settings) {
                 return self::defaultSettings();
             }
+
             return collect($settings)
-            ->filter(function($item, $key) {
-                return in_array($key, array_keys(self::defaultSettings())) == true;
-            })
-            ->map(function($item, $key) {
-                if($key == 'compose_settings') {
-                    $cs = self::defaultSettings()['compose_settings'];
-                    $ms = is_array($item) ? $item : [];
-                    return array_merge($cs, $ms);
-                }
-
-                if($key == 'other') {
-                    $other =  self::defaultSettings()['other'];
-                    $mo = is_array($item) ? $item : [];
-                    return array_merge($other, $mo);
-                }
-                return $item;
-            });
+                ->filter(function ($item, $key) {
+                    return in_array($key, array_keys(self::defaultSettings())) == true;
+                })
+                ->map(function ($item, $key) {
+                    if ($key == 'compose_settings') {
+                        $cs = self::defaultSettings()['compose_settings'];
+                        $ms = is_array($item) ? $item : [];
+
+                        return array_merge($cs, $ms);
+                    }
+
+                    if ($key == 'other') {
+                        $other = self::defaultSettings()['other'];
+                        $mo = is_array($item) ? $item : [];
+
+                        return array_merge($other, $mo);
+                    }
+
+                    return $item;
+                });
         });
     }
 
+    public static function getAccountSettings($pid)
+    {
+        $key = self::CACHE_PF_ACCT_SETTINGS_KEY.$pid;
+
+        return Cache::remember($key, 14400, function () use ($pid) {
+            $user = User::with('profile')->whereProfileId($pid)->whereNull('status')->first();
+            if (! $user) {
+                return [];
+            }
+
+            $settings = $user->settings;
+            $other = array_merge(self::defaultSettings()['other'], $settings->other ?? []);
+
+            return [
+                'reduce_motion' => (bool) $settings->reduce_motion,
+                'high_contrast_mode' => (bool) $settings->high_contrast_mode,
+                'video_autoplay' => (bool) $settings->video_autoplay,
+                'media_descriptions' => (bool) $settings->media_descriptions,
+                'crawlable' => (bool) $settings->crawlable,
+                'show_profile_follower_count' => (bool) $settings->show_profile_follower_count,
+                'show_profile_following_count' => (bool) $settings->show_profile_following_count,
+                'public_dm' => (bool) $settings->public_dm,
+                'disable_embeds' => (bool) $other['disable_embeds'],
+                'show_atom' => (bool) $settings->show_atom,
+                'is_suggestable' => (bool) $user->profile->is_suggestable,
+                'indexable' => (bool) $user->profile->indexable,
+            ];
+        });
+    }
+
+    public static function forgetAccountSettings($pid)
+    {
+        return Cache::forget(self::CACHE_PF_ACCT_SETTINGS_KEY.$pid);
+    }
+
     public static function canEmbed($id)
     {
-        return self::settings($id)['other']['disable_embeds'] == false;
+        $res = self::getAccountSettings($id);
+        if (! $res || ! isset($res['disable_embeds'])) {
+            return false;
+        }
+
+        return ! $res['disable_embeds'];
     }
 
     public static function defaultSettings()
@@ -123,7 +172,7 @@ class AccountService
             'compose_settings' => [
                 'default_scope' => 'public',
                 'default_license' => 1,
-                'media_descriptions' => false
+                'media_descriptions' => false,
             ],
             'other' => [
                 'advanced_atom' => false,
@@ -134,7 +183,7 @@ class AccountService
                 'hide_groups' => false,
                 'hide_stories' => false,
                 'disable_cw' => false,
-            ]
+            ],
         ];
     }
 
@@ -142,13 +191,13 @@ class AccountService
     {
         $profile = Profile::find($id);
 
-        if(!$profile) {
+        if (! $profile) {
             return false;
         }
 
-        $key = self::CACHE_KEY . 'pcs:' . $id;
+        $key = self::CACHE_KEY.'pcs:'.$id;
 
-        if(Cache::has($key)) {
+        if (Cache::has($key)) {
             return;
         }
 
@@ -162,23 +211,26 @@ class AccountService
         $profile->save();
 
         Cache::put($key, 1, 900);
+
         return true;
     }
 
     public static function usernameToId($username)
     {
-        $key = self::CACHE_KEY . 'u2id:' . hash('sha256', $username);
-        return Cache::remember($key, 14400, function() use($username) {
+        $key = self::CACHE_KEY.'u2id:'.hash('sha256', $username);
+
+        return Cache::remember($key, 14400, function () use ($username) {
             $s = Str::of($username);
-            if($s->contains('@') && !$s->startsWith('@')) {
+            if ($s->contains('@') && ! $s->startsWith('@')) {
                 $username = "@{$username}";
             }
             $profile = DB::table('profiles')
                 ->whereUsername($username)
                 ->first();
-            if(!$profile) {
+            if (! $profile) {
                 return null;
             }
+
             return (string) $profile->id;
         });
     }
@@ -186,19 +238,20 @@ class AccountService
     public static function hiddenFollowers($id)
     {
         $account = self::get($id, true);
-        if(!$account || !isset($account['local']) || $account['local'] == false) {
+        if (! $account || ! isset($account['local']) || $account['local'] == false) {
             return false;
         }
 
-        return Cache::remember('pf:acct:settings:hidden-followers:' . $id, 43200, function() use($id) {
+        return Cache::remember('pf:acct:settings:hidden-followers:'.$id, 43200, function () use ($id) {
             $user = User::whereProfileId($id)->first();
-            if(!$user) {
+            if (! $user) {
                 return false;
             }
             $settings = UserSetting::whereUserId($user->id)->first();
-            if($settings) {
+            if ($settings) {
                 return $settings->show_profile_follower_count == false;
             }
+
             return false;
         });
     }
@@ -206,60 +259,66 @@ class AccountService
     public static function hiddenFollowing($id)
     {
         $account = self::get($id, true);
-        if(!$account || !isset($account['local']) || $account['local'] == false) {
+        if (! $account || ! isset($account['local']) || $account['local'] == false) {
             return false;
         }
 
-        return Cache::remember('pf:acct:settings:hidden-following:' . $id, 43200, function() use($id) {
+        return Cache::remember('pf:acct:settings:hidden-following:'.$id, 43200, function () use ($id) {
             $user = User::whereProfileId($id)->first();
-            if(!$user) {
+            if (! $user) {
                 return false;
             }
             $settings = UserSetting::whereUserId($user->id)->first();
-            if($settings) {
+            if ($settings) {
                 return $settings->show_profile_following_count == false;
             }
+
             return false;
         });
     }
 
     public static function setLastActive($id = false)
     {
-        if(!$id) { return; }
-        $key = 'user:last_active_at:id:' . $id;
-        if(!Cache::has($key)) {
+        if (! $id) {
+            return;
+        }
+        $key = 'user:last_active_at:id:'.$id;
+        if (! Cache::has($key)) {
             $user = User::find($id);
-            if(!$user) { return; }
+            if (! $user) {
+                return;
+            }
             $user->last_active_at = now();
             $user->save();
             Cache::put($key, 1, 14400);
         }
-        return;
+
     }
 
     public static function blocksDomain($pid, $domain = false)
     {
-        if(!$domain) {
+        if (! $domain) {
             return;
         }
 
         return UserDomainBlock::whereProfileId($pid)->whereDomain($domain)->exists();
     }
 
-    public static function formatNumber($num) {
-        if(!$num || $num < 1) {
-            return "0";
+    public static function formatNumber($num)
+    {
+        if (! $num || $num < 1) {
+            return '0';
         }
         $num = intval($num);
         $formatter = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
         $formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, 1);
 
         if ($num >= 1000000000) {
-            return $formatter->format($num / 1000000000) . 'B';
-        } else if ($num >= 1000000) {
-            return $formatter->format($num / 1000000) . 'M';
+            return $formatter->format($num / 1000000000).'B';
+        } elseif ($num >= 1000000) {
+            return $formatter->format($num / 1000000).'M';
         } elseif ($num >= 1000) {
-            return $formatter->format($num / 1000) . 'K';
+            return $formatter->format($num / 1000).'K';
         } else {
             return $formatter->format($num);
         }
@@ -269,14 +328,17 @@ class AccountService
     {
         $account = self::get($id, true);
 
-        if(!$account) return "";
+        if (! $account) {
+            return '';
+        }
 
-        $posts = self::formatNumber($account['statuses_count']) . ' Posts, ';
-        $following = self::formatNumber($account['following_count']) . ' Following, ';
-        $followers = self::formatNumber($account['followers_count']) . ' Followers';
+        $posts = self::formatNumber($account['statuses_count']).' Posts, ';
+        $following = self::formatNumber($account['following_count']).' Following, ';
+        $followers = self::formatNumber($account['followers_count']).' Followers';
         $note = $account['note'] && strlen($account['note']) ?
-            ' · ' . \Purify::clean(strip_tags(str_replace("\n", '', str_replace("\r", '', $account['note'])))) :
+            ' · '.\Purify::clean(strip_tags(str_replace("\n", '', str_replace("\r", '', $account['note'])))) :
             '';
-        return $posts . $following . $followers . $note;
+
+        return $posts.$following.$followers.$note;
     }
 }

+ 8 - 0
resources/views/settings/privacy.blade.php

@@ -97,6 +97,14 @@
       <p class="text-muted small help-text">Display following count on profile</p>
     </div>
 
+    <div class="form-check pb-3">
+      <input class="form-check-input" type="checkbox" name="disable_embeds" id="disable_embeds" {{$settings->disable_embeds ? 'checked=""':''}}>
+      <label class="form-check-label font-weight-bold" for="disable_embeds">
+        {{__('Disable Embeds')}}
+      </label>
+      <p class="text-muted small help-text">Disable post and profile embeds</p>
+    </div>
+
     @if(!$settings->is_private)
     <div class="form-check pb-3">
       <input class="form-check-input" type="checkbox" name="show_atom" id="show_atom" {{$settings->show_atom ? 'checked=""':''}}>