|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
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;
|
fix: add missing use imports to resolve phpstan class.notFound errors
Add missing imports for Log, Cache, DB, FollowerService, StatusService,
LikeService, ReblogService, UserFilterService, AdminProfile, OauthClient,
and fix StatusTimelineTransformer reference (class didn't exist, replaced
with StatusTransformer).
4 weeks ago
|
|
|
use App\OauthClient;
|
|
|
|
|
use App\ProfileSponsor;
|
|
|
|
|
use App\Services\AccountService;
|
|
|
|
|
use App\UserSetting;
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
|
use Illuminate\Support\Facades\Cookie;
|
fix: add missing use imports to resolve phpstan class.notFound errors
Add missing imports for Log, Cache, DB, FollowerService, StatusService,
LikeService, ReblogService, UserFilterService, AdminProfile, OauthClient,
and fix StatusTimelineTransformer reference (class didn't exist, replaced
with StatusTransformer).
4 weeks ago
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use Illuminate\Support\Facades\Redis;
|
|
|
|
|
use Illuminate\Support\Str;
|
|
|
|
|
|
|
|
|
|
class SettingsController extends Controller
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
$this->validate($request, [
|
|
|
|
|
'confirm' => 'required|accepted',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$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);
|
|
|
|
|
DB::table('oauth_access_tokens')->where('user_id', $user->id)->delete();
|
|
|
|
|
DB::table('oauth_refresh_tokens')->where('user_id', $user->id)->delete();
|
|
|
|
|
OauthClient::where('user_id', $user->id)->delete();
|
|
|
|
|
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;
|
|
|
|
|
$userSettings = UserSetting::firstOrCreate([
|
|
|
|
|
'user_id' => $uid,
|
|
|
|
|
]);
|
|
|
|
|
if (! $userSettings || ! $userSettings->other) {
|
|
|
|
|
$userSettings = [
|
|
|
|
|
'enable_reblogs' => false,
|
|
|
|
|
'photo_reblogs_only' => false,
|
|
|
|
|
];
|
|
|
|
|
} else {
|
|
|
|
|
$userSettings = array_merge([
|
|
|
|
|
'enable_reblogs' => false,
|
|
|
|
|
'photo_reblogs_only' => false,
|
|
|
|
|
],
|
|
|
|
|
$userSettings->other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return view('settings.timeline', compact('top', 'replies', 'userSettings'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function updateTimelineSettings(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$pid = $request->user()->profile_id;
|
|
|
|
|
$uid = $request->user()->id;
|
|
|
|
|
$this->validate($request, [
|
|
|
|
|
'enable_reblogs' => 'sometimes',
|
|
|
|
|
'photo_reblogs_only' => 'sometimes',
|
|
|
|
|
]);
|
|
|
|
|
Redis::zrem('pf:tl:top', $pid);
|
|
|
|
|
Redis::zrem('pf:tl:replies', $pid);
|
|
|
|
|
$userSettings = UserSetting::firstOrCreate([
|
|
|
|
|
'user_id' => $uid,
|
|
|
|
|
]);
|
|
|
|
|
if ($userSettings->other) {
|
|
|
|
|
$other = $userSettings->other;
|
|
|
|
|
$other['enable_reblogs'] = $request->has('enable_reblogs');
|
|
|
|
|
$other['photo_reblogs_only'] = $request->has('photo_reblogs_only');
|
|
|
|
|
} else {
|
|
|
|
|
$other['enable_reblogs'] = $request->has('enable_reblogs');
|
|
|
|
|
$other['photo_reblogs_only'] = $request->has('photo_reblogs_only');
|
|
|
|
|
}
|
|
|
|
|
$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!');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function filtersHome(Request $request)
|
|
|
|
|
{
|
|
|
|
|
return view('settings.filters.home');
|
|
|
|
|
}
|
|
|
|
|
}
|