diff --git a/app/Http/Controllers/Admin/AdminReportController.php b/app/Http/Controllers/Admin/AdminReportController.php index 2af1b2bee..d2625acff 100644 --- a/app/Http/Controllers/Admin/AdminReportController.php +++ b/app/Http/Controllers/Admin/AdminReportController.php @@ -4,8 +4,12 @@ namespace App\Http\Controllers\Admin; use Cache; use App\Report; +use App\User; use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Redis; +use App\Services\AccountService; +use App\Services\StatusService; trait AdminReportController { @@ -33,6 +37,7 @@ trait AdminReportController $report = Report::findOrFail($id); $this->handleReportAction($report, $action); + Cache::forget('admin-dash:reports:list-cache'); return response()->json(['msg'=> 'Success']); } @@ -52,17 +57,20 @@ trait AdminReportController $item->is_nsfw = true; $item->save(); $report->nsfw = true; + StatusService::del($item->id); break; case 'unlist': $item->visibility = 'unlisted'; $item->save(); Cache::forget('profiles:private'); + StatusService::del($item->id); break; case 'delete': // Todo: fire delete job $report->admin_seen = null; + StatusService::del($item->id); break; case 'shadowban': @@ -115,4 +123,55 @@ trait AdminReportController ]; return response()->json($res); } + + public function reportMailVerifications(Request $request) + { + $ids = Redis::smembers('email:manual'); + $ignored = Redis::smembers('email:manual-ignored'); + $reports = []; + if($ids) { + $reports = collect($ids) + ->filter(function($id) use($ignored) { + return !in_array($id, $ignored); + }) + ->map(function($id) { + $account = AccountService::get($id); + $user = User::whereProfileId($id)->first(); + if(!$user) { + return []; + } + $account['email'] = $user->email; + return $account; + }) + ->filter(function($res) { + return isset($res['id']); + }) + ->values(); + } + return view('admin.reports.mail_verification', compact('reports', 'ignored')); + } + + public function reportMailVerifyIgnore(Request $request) + { + $id = $request->input('id'); + Redis::sadd('email:manual-ignored', $id); + return redirect('/i/admin/reports'); + } + + public function reportMailVerifyApprove(Request $request) + { + $id = $request->input('id'); + $user = User::whereProfileId($id)->firstOrFail(); + Redis::srem('email:manual', $id); + Redis::srem('email:manual-ignored', $id); + $user->email_verified_at = now(); + $user->save(); + return redirect('/i/admin/reports'); + } + + public function reportMailVerifyClearIgnored(Request $request) + { + Redis::del('email:manual-ignored'); + return [200]; + } } diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 8c9d7e218..f31bc823a 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -17,6 +17,7 @@ use App\{ use DB, Cache; use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Redis; use App\Http\Controllers\Admin\{ AdminDiscoverController, AdminInstanceController, @@ -28,12 +29,13 @@ use App\Http\Controllers\Admin\{ }; use Illuminate\Validation\Rule; use App\Services\AdminStatsService; +use App\Services\StatusService; use App\Services\StoryService; class AdminController extends Controller { use AdminReportController, - AdminDiscoverController, + AdminDiscoverController, AdminMediaController, AdminSettingsController, AdminInstanceController, @@ -54,9 +56,15 @@ class AdminController extends Controller public function statuses(Request $request) { - $statuses = Status::orderBy('id', 'desc')->simplePaginate(10); - - return view('admin.statuses.home', compact('statuses')); + $statuses = Status::orderBy('id', 'desc')->cursorPaginate(10); + $data = $statuses->map(function($status) { + return StatusService::get($status->id, false); + }) + ->filter(function($s) { + return $s; + }) + ->toArray(); + return view('admin.statuses.home', compact('statuses', 'data')); } public function showStatus(Request $request, $id) @@ -69,17 +77,45 @@ class AdminController extends Controller public function reports(Request $request) { $filter = $request->input('filter') == 'closed' ? 'closed' : 'open'; - $reports = Report::whereHas('status') - ->whereHas('reportedUser') - ->whereHas('reporter') - ->orderBy('created_at','desc') - ->when($filter, function($q, $filter) { - return $filter == 'open' ? - $q->whereNull('admin_seen') : - $q->whereNotNull('admin_seen'); - }) - ->paginate(6); - return view('admin.reports.home', compact('reports')); + $page = $request->input('page') ?? 1; + + $ai = Cache::remember('admin-dash:reports:ai-count', 3600, function() { + return AccountInterstitial::whereNotNull('appeal_requested_at')->whereNull('appeal_handled_at')->count(); + }); + + $spam = Cache::remember('admin-dash:reports:spam-count', 3600, function() { + return AccountInterstitial::whereType('post.autospam')->whereNull('appeal_handled_at')->count(); + }); + + $mailVerifications = Redis::scard('email:manual'); + + if($filter == 'open' && $page == 1) { + $reports = Cache::remember('admin-dash:reports:list-cache', 300, function() use($page, $filter) { + return Report::whereHas('status') + ->whereHas('reportedUser') + ->whereHas('reporter') + ->orderBy('created_at','desc') + ->when($filter, function($q, $filter) { + return $filter == 'open' ? + $q->whereNull('admin_seen') : + $q->whereNotNull('admin_seen'); + }) + ->paginate(6); + }); + } else { + $reports = Report::whereHas('status') + ->whereHas('reportedUser') + ->whereHas('reporter') + ->orderBy('created_at','desc') + ->when($filter, function($q, $filter) { + return $filter == 'open' ? + $q->whereNull('admin_seen') : + $q->whereNotNull('admin_seen'); + }) + ->paginate(6); + } + + return view('admin.reports.home', compact('reports', 'ai', 'spam', 'mailVerifications')); } public function showReport(Request $request, $id) @@ -143,7 +179,7 @@ class AdminController extends Controller Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $appeal->user->profile_id); Cache::forget('pf:bouncer_v0:recent_by_pid:' . $appeal->user->profile_id); - + Cache::forget('admin-dash:reports:spam-count'); return redirect('/i/admin/reports/autospam'); } @@ -156,8 +192,11 @@ class AdminController extends Controller $appeal->appeal_handled_at = now(); $appeal->save(); + StatusService::del($status->id); + Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $appeal->user->profile_id); Cache::forget('pf:bouncer_v0:recent_by_pid:' . $appeal->user->profile_id); + Cache::forget('admin-dash:reports:spam-count'); return redirect('/i/admin/reports/autospam'); } @@ -176,7 +215,7 @@ class AdminController extends Controller if($action == 'dismiss') { $appeal->appeal_handled_at = now(); $appeal->save(); - + Cache::forget('admin-dash:reports:ai-count'); return redirect('/i/admin/reports/appeals'); } @@ -201,6 +240,8 @@ class AdminController extends Controller $appeal->appeal_handled_at = now(); $appeal->save(); + StatusService::del($status->id); + Cache::forget('admin-dash:reports:ai-count'); return redirect('/i/admin/reports/appeals'); } diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index 23bb687ba..b9f86a639 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; use App\{ AccountInterstitial, + Bookmark, DirectMessage, DiscoverCategory, Hashtag, @@ -19,6 +20,7 @@ use App\{ UserFilter, }; use Auth,Cache; +use Illuminate\Support\Facades\Redis; use Carbon\Carbon; use League\Fractal; use App\Transformer\Api\{ @@ -345,14 +347,18 @@ class InternalApiController extends Controller public function bookmarks(Request $request) { - $statuses = Auth::user()->profile - ->bookmarks() - ->withCount(['likes','comments']) - ->orderBy('created_at', 'desc') - ->simplePaginate(10); - - $resource = new Fractal\Resource\Collection($statuses, new StatusTransformer()); - $res = $this->fractal->createData($resource)->toArray(); + $res = Bookmark::whereProfileId($request->user()->profile_id) + ->orderByDesc('created_at') + ->simplePaginate(10) + ->map(function($bookmark) { + $status = StatusService::get($bookmark->status_id); + $status['bookmarked_at'] = $bookmark->created_at->format('c'); + return $status; + }) + ->filter(function($bookmark) { + return isset($bookmark['id']); + }) + ->values(); return response()->json($res); } @@ -456,4 +462,18 @@ class InternalApiController extends Controller $template = $status->in_reply_to_id ? 'status.reply' : 'status.remote'; return view($template, compact('user', 'status')); } + + public function requestEmailVerification(Request $request) + { + $pid = $request->user()->profile_id; + $exists = Redis::sismember('email:manual', $pid); + return view('account.email.request_verification', compact('exists')); + } + + public function requestEmailVerificationStore(Request $request) + { + $pid = $request->user()->profile_id; + Redis::sadd('email:manual', $pid); + return redirect('/i/verify-email')->with(['status' => 'Successfully sent manual verification request!']); + } } diff --git a/resources/views/account/verify_email.blade.php b/resources/views/account/verify_email.blade.php index 3286a1e84..4ed3997d2 100644 --- a/resources/views/account/verify_email.blade.php +++ b/resources/views/account/verify_email.blade.php @@ -13,19 +13,35 @@

{{ session('error') }}

@endif + + @if(Auth::user()->email_verified_at) +

Your email is already verified. Click here to go home.

+ @else
Confirm Email Address
-

You need to confirm your email address ({{Auth::user()->email}}) before you can proceed.

-

You can change your email address here.

-

If you don't recieve an email within 30 minutes, you can contact the administrator.

-
+

You need to confirm your email address {{Auth::user()->email}} before you can proceed.

+ @if(!$recentSent)
@csrf
+ @else + + @endif +

Click here to change your email address.

+ + @if($recentSent) +
+
+

If you are experiencing issues receiving your email confirmation, you can request manual verification.

+
+
+ @endif + + @endif @endsection diff --git a/resources/views/admin/reports/home.blade.php b/resources/views/admin/reports/home.blade.php index 254772ce2..8f881567d 100644 --- a/resources/views/admin/reports/home.blade.php +++ b/resources/views/admin/reports/home.blade.php @@ -15,11 +15,14 @@ @endif - @php($ai = App\AccountInterstitial::whereNotNull('appeal_requested_at')->whereNull('appeal_handled_at')->count()) - @php($spam = App\AccountInterstitial::whereType('post.autospam')->whereNull('appeal_handled_at')->count()) - @if($ai || $spam) + + @if($ai || $spam || $mailVerifications)
+ +

{{$mailVerifications}}

+ Email Verify {{$mailVerifications == 1 ? 'Request' : 'Requests'}} +

{{$ai}}

Appeal {{$ai == 1 ? 'Request' : 'Requests'}} diff --git a/resources/views/admin/reports/mail_verification.blade.php b/resources/views/admin/reports/mail_verification.blade.php new file mode 100644 index 000000000..35ac8ccba --- /dev/null +++ b/resources/views/admin/reports/mail_verification.blade.php @@ -0,0 +1,75 @@ +@extends('admin.partial.template-full') + +@section('section') +
+
+
+
+ @foreach($reports as $report) +
+
+ +
+

{{ $report['username'] }}

+

{{ $report['email'] }}

+
+
+ + +
+
+
+ @endforeach + + @if(count($reports) == 0) +
+

No email verification requests found!

+
+ @endif +
+
+
+@endsection + +@push('scripts') + +@endpush diff --git a/routes/web.php b/routes/web.php index 0a1b50850..d0ac72ecb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,6 +14,10 @@ Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->group(functio Route::get('reports/appeals', 'AdminController@appeals'); Route::get('reports/appeal/{id}', 'AdminController@showAppeal'); Route::post('reports/appeal/{id}', 'AdminController@updateAppeal'); + Route::get('reports/email-verifications', 'AdminController@reportMailVerifications'); + Route::post('reports/email-verifications/ignore', 'AdminController@reportMailVerifyIgnore'); + Route::post('reports/email-verifications/approve', 'AdminController@reportMailVerifyApprove'); + Route::post('reports/email-verifications/clear-ignored', 'AdminController@reportMailVerifyClearIgnored'); Route::redirect('stories', '/stories/list'); Route::get('stories/list', 'AdminController@stories')->name('admin.stories'); Route::redirect('statuses', '/statuses/list'); @@ -273,6 +277,8 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::get('verify-email', 'AccountController@verifyEmail'); Route::post('verify-email', 'AccountController@sendVerifyEmail'); + Route::get('verify-email/request', 'InternalApiController@requestEmailVerification'); + Route::post('verify-email/request', 'InternalApiController@requestEmailVerificationStore'); Route::get('confirm-email/{userToken}/{randomToken}', 'AccountController@confirmVerifyEmail'); Route::get('auth/sudo', 'AccountController@sudoMode');