Add disable_embeds setting, and fix cache invalidation in other settings

This commit is contained in:
Daniel Supernault 2024-06-04 03:46:06 -06:00
parent e97b5b7a69
commit c5e7e91777
No known key found for this signature in database
GPG key ID: 23740873EE6F76A1
8 changed files with 475 additions and 383 deletions

View file

@ -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) {

View file

@ -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']);
}

View file

@ -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');

View file

@ -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!');
}

View file

@ -2,270 +2,275 @@
namespace App\Http\Controllers;
use App\AccountLog;
use App\Following;
use App\ProfileSponsor;
use App\Report;
use App\UserFilter;
use App\UserSetting;
use Auth, Cookie, DB, Cache, Purify;
use Illuminate\Support\Facades\Redis;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Http\Controllers\Settings\{
ExportSettings,
LabsSettings,
HomeSettings,
PrivacySettings,
RelationshipSettings,
SecuritySettings
};
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\Services\AccountService;
use App\UserSetting;
use Auth;
use Cache;
use Carbon\Carbon;
use Cookie;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
class SettingsController extends Controller
{
use ExportSettings,
LabsSettings,
HomeSettings,
PrivacySettings,
RelationshipSettings,
SecuritySettings;
use ExportSettings,
HomeSettings,
LabsSettings,
PrivacySettings,
RelationshipSettings,
SecuritySettings;
public function __construct()
{
$this->middleware('auth');
}
public function __construct()
{
$this->middleware('auth');
}
public function accessibility()
{
$settings = Auth::user()->settings;
public function accessibility()
{
$settings = Auth::user()->settings;
return view('settings.accessibility', compact('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();
}
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!');
}
return redirect(route('settings.accessibility'))->with('status', 'Settings successfully updated!');
}
public function notifications()
{
return view('settings.notifications');
}
public function notifications()
{
return view('settings.notifications');
}
public function applications()
{
return view('settings.applications');
}
public function applications()
{
return view('settings.applications');
}
public function dataImport()
{
return view('settings.import.home');
}
public function dataImport()
{
return view('settings.import.home');
}
public function dataImportInstagram()
{
abort(404);
}
public function dataImportInstagram()
{
abort(404);
}
public function developers()
{
return view('settings.developers');
}
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);
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');
}
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 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');
public function removeAccountPermanent(Request $request)
{
$user = Auth::user();
abort_if($user->is_admin, 403);
return view('settings.remove.permanent');
}
return redirect('/');
}
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 removeAccountPermanent(Request $request)
{
$user = Auth::user();
abort_if($user->is_admin, 403);
public function requestFullExport(Request $request)
{
$user = Auth::user();
return view('settings.export.show');
}
return view('settings.remove.permanent');
}
public function metroDarkMode(Request $request)
{
$this->validate($request, [
'mode' => 'required|string|in:light,dark'
]);
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');
$mode = $request->input('mode');
return redirect('/');
}
if($mode == 'dark') {
$cookie = Cookie::make('dark-mode', 'true', 43800);
} else {
$cookie = Cookie::forget('dark-mode');
}
public function requestFullExport(Request $request)
{
$user = Auth::user();
return response()->json([200])->cookie($cookie);
}
return view('settings.export.show');
}
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;
$userSettings = UserSetting::firstOrCreate([
'user_id' => $uid
public function metroDarkMode(Request $request)
{
$this->validate($request, [
'mode' => 'required|string|in:light,dark',
]);
if(!$userSettings || !$userSettings->other) {
$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;
$userSettings = UserSetting::firstOrCreate([
'user_id' => $uid,
]);
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'));
}
return redirect(route('settings'))->with('status', 'Timeline settings successfully updated!');
}
public function updateMediaSettings(Request $request)
{
$this->validate($request, [
'default' => 'required|int|min:1|max:16',
'sync' => 'nullable',
'media_descriptions' => 'nullable'
]);
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,
];
$license = $request->input('default');
$sync = $request->input('sync') == 'on';
$media_descriptions = $request->input('media_descriptions') == 'on';
$uid = $request->user()->id;
return view('settings.media', compact('compose'));
}
$setting = UserSetting::whereUserId($uid)->firstOrFail();
$compose = is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings;
$changed = false;
public function updateMediaSettings(Request $request)
{
$this->validate($request, [
'default' => 'required|int|min:1|max:16',
'sync' => 'nullable',
'media_descriptions' => 'nullable',
]);
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);
}
}
$license = $request->input('default');
$sync = $request->input('sync') == 'on';
$media_descriptions = $request->input('media_descriptions') == 'on';
$uid = $request->user()->id;
if(!isset($compose['default_license']) || $compose['default_license'] !== $license) {
$compose['default_license'] = (int) $license;
$changed = true;
}
$setting = UserSetting::whereUserId($uid)->firstOrFail();
$compose = is_string($setting->compose_settings) ? json_decode($setting->compose_settings, true) : $setting->compose_settings;
$changed = false;
if(!isset($compose['media_descriptions']) || $compose['media_descriptions'] !== $media_descriptions) {
$compose['media_descriptions'] = $media_descriptions;
$changed = true;
}
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.';
if($changed) {
$setting->compose_settings = $compose;
$setting->save();
Cache::forget('profile:compose:settings:' . $request->user()->id);
}
return redirect(route('settings'))
->with('error', $msg);
}
}
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.');
}
if (! isset($compose['default_license']) || $compose['default_license'] !== $license) {
$compose['default_license'] = (int) $license;
$changed = true;
}
return redirect(route('settings'))->with('status', 'Media settings successfully updated!');
}
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!');
}
}

View file

@ -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) {

View file

@ -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;
});
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;
});
});
}
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;
}
}

View file

@ -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=""':''}}>