From 298475d7de6f4ac751b45f045eed970e6cfe625a Mon Sep 17 00:00:00 2001 From: Spitfire Date: Thu, 22 Aug 2024 10:44:18 -0600 Subject: [PATCH 01/12] PostRecove --- .../Campaign/PostRecoveryController.php | 77 ------------------- .../Campaign/RecoveryController.php | 56 ++++++-------- lang/en/campaigns/recovery.php | 14 +--- .../views/campaigns/recovery/_table.blade.php | 23 ++++++ .../views/campaigns/recovery/index.blade.php | 36 ++------- routes/campaigns/campaign.php | 3 - 6 files changed, 59 insertions(+), 150 deletions(-) delete mode 100644 app/Http/Controllers/Campaign/PostRecoveryController.php create mode 100644 resources/views/campaigns/recovery/_table.blade.php diff --git a/app/Http/Controllers/Campaign/PostRecoveryController.php b/app/Http/Controllers/Campaign/PostRecoveryController.php deleted file mode 100644 index 806396bbef..0000000000 --- a/app/Http/Controllers/Campaign/PostRecoveryController.php +++ /dev/null @@ -1,77 +0,0 @@ -middleware('auth'); - - $this->service = $service; - } - - /** - * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\JsonResponse - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Campaign $campaign) - { - $this->authorize('recover', $campaign); - - Datagrid::layout(\App\Renderers\Layouts\Campaign\PostRecovery::class) - ->permissions(false); - - $rows = $campaign->posts()->onlyTrashed() - ->sort(request()->only(['o', 'k']), ['deleted_at' => 'DESC']) - ->whereDate('posts.deleted_at', '>=', Carbon::today()->subDays(config('entities.hard_delete_posts'))) - ->paginate(); - - // Ajax Datagrid - if (request()->ajax()) { - $html = view('layouts.datagrid._table') - ->with('rows', $rows) - ->render(); - return response()->json([ - 'success' => true, - 'html' => $html, - ]); - } - $isPost = true; - return view('campaigns.recovery.index', compact('rows', 'campaign', 'isPost')); - } - - public function recover(Request $request, Campaign $campaign) - { - if (request()->ajax()) { - return response()->json(['success' => true]); - } - if (!$campaign->boosted()) { - return redirect() - ->route('recovery', $campaign) - ->with('boosted-pitch', true) - ; - } - - try { - $count = $this->service->recover($request->get('model', [])); - return redirect() - ->route('recovery.posts', $campaign) - ->with('success', trans_choice('campaigns/recovery.posts.success', $count, ['count' => $count])); - } catch (Exception $e) { - return redirect() - ->route('recovery.posts', $campaign) - ->with('error', __('campaigns/recovery.posts.error')); - } - } -} diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index dd4a78f4e2..9b0d1cba8b 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -2,24 +2,25 @@ namespace App\Http\Controllers\Campaign; -use App\Facades\Datagrid; use App\Http\Controllers\Controller; use App\Models\Campaign; -use App\Models\Entity; -use App\Services\Entity\RecoveryService; -use Carbon\Carbon; +use App\Services\Entity\RecoveryService as EntityRecoveryService; +use App\Services\Posts\RecoveryService; use Exception; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class RecoveryController extends Controller { - protected RecoveryService $service; + protected RecoveryService $postService; + protected EntityRecoveryService $entityService; - public function __construct(RecoveryService $service) + public function __construct(RecoveryService $postService, EntityRecoveryService $entityService) { $this->middleware('auth'); - $this->service = $service; + $this->postService = $postService; + $this->entityService = $entityService; } /** @@ -30,34 +31,24 @@ public function index(Campaign $campaign) { $this->authorize('recover', $campaign); - Datagrid::layout(\App\Renderers\Layouts\Campaign\Recovery::class) - ->permissions(false); + $elements = DB::select( + 'select id, name, deleted_at, deleted_by, "entity" as type + from entities + where deleted_at is not null and campaign_id = ' . $campaign->id . ' + union all + select p.id, p.name, p.deleted_at, p.deleted_by, "post" as type + from posts as p + left join entities as e on e.id = p.entity_id + where p.deleted_at is not null and e.deleted_at is null and e.campaign_id = ' . $campaign->id . + ' order by deleted_at DESC' - $rows = Entity::onlyTrashed() - ->with('image') - ->sort(request()->only(['o', 'k']), ['deleted_at' => 'DESC']) - ->whereDate('deleted_at', '>=', Carbon::today()->subDays(config('entities.hard_delete'))) - ->paginate(); + ); - // Ajax Datagrid - if (request()->ajax()) { - $html = view('layouts.datagrid._table') - ->with('rows', $rows) - ->render(); - return response()->json([ - 'success' => true, - 'html' => $html, - ]); - } - - return view('campaigns.recovery.index', compact('rows', 'campaign')); + return view('campaigns.recovery.index', compact('elements', 'campaign')); } public function recover(Request $request, Campaign $campaign) { - if (request()->ajax()) { - return response()->json(['success' => true]); - } if (!$campaign->boosted()) { return redirect() ->route('recovery', $campaign) @@ -66,10 +57,13 @@ public function recover(Request $request, Campaign $campaign) } try { - $count = $this->service->recover($request->get('model', [])); + $countEntity = $this->entityService->recover($request->get('entity', [])); + $countPost = $this->postService->recover($request->get('post', [])); + + $count = $countEntity + $countPost; return redirect() ->route('recovery', $campaign) - ->with('success', trans_choice('campaigns/recovery.success', $count, ['count' => $count])); + ->with('success', trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])); } catch (Exception $e) { return redirect() ->route('recovery', $campaign) diff --git a/lang/en/campaigns/recovery.php b/lang/en/campaigns/recovery.php index 55ebbb7c7d..d4ba1e1c02 100644 --- a/lang/en/campaigns/recovery.php +++ b/lang/en/campaigns/recovery.php @@ -6,18 +6,10 @@ ], 'error' => 'An error occurred trying to recover entities.', 'fields' => [ - 'deleted' => 'Deleted', + 'deleted' => 'Deleted', + 'deleted_at' => 'Deleted :date' ], 'helper' => 'Deleted entities of the campaign can be recovered for up to :count days. Entities deleted while the campaign isn\'t upgraded to premium status are still recoverable once the campaign is upgraded.', - 'post-title' => 'Post Recovery', - 'posts' => [ - 'error' => 'An error occurred trying to recover posts.', - 'success' => '{1} :count post was recovered.|[2,*] :count posts were recovered.', - ], - 'success' => '{1} :count entity was recovered.|[2,*] :count entities were recovered.', + 'success_v2' => '{1} :count post or entity was recovered.|[2,*] :count posts and/or entities were recovered.', 'title' => 'Entity Recovery', - 'toggle' => [ - 'entity' => 'Switch to entity recovery', - 'post' => 'Switch to post recovery', - ], ]; diff --git a/resources/views/campaigns/recovery/_table.blade.php b/resources/views/campaigns/recovery/_table.blade.php new file mode 100644 index 0000000000..98fe82cf43 --- /dev/null +++ b/resources/views/campaigns/recovery/_table.blade.php @@ -0,0 +1,23 @@ +
+ @foreach ($elements as $element) +
+
+
+ +
+
{{ $element->name }}
+ +
+ @if ($element->type == 'entity') + {{ __('crud.fields.entity') }} + @else + {{ __('entities.post') }} + @endif +
+
+
+ {{ __('campaigns/recovery.fields.deleted_at', ['date' => \Carbon\Carbon::createFromTimeStamp(strtotime($element->deleted_at))->diffForHumans()]) }} +
+
+ @endforeach +
diff --git a/resources/views/campaigns/recovery/index.blade.php b/resources/views/campaigns/recovery/index.blade.php index f5bfc12e12..d366b8fffa 100644 --- a/resources/views/campaigns/recovery/index.blade.php +++ b/resources/views/campaigns/recovery/index.blade.php @@ -9,51 +9,31 @@ ]) @section('content') - +
@include('partials.errors')

- @if (isset($isPost)) - {{ __('campaigns/recovery.post-title') }} - @else {{ __('campaigns/recovery.title') }} - @endif

+ - @if(isset($isPost)) - - - {{ __('campaigns/recovery.toggle.entity') }} - - @else - - - {{ __('campaigns/recovery.toggle.post') }} - - @endif
@if (session()->get('boosted-pitch')) @endif - - @if(Datagrid::hasBulks()) - -
- @include('layouts.datagrid._table') -
-
- @else -
- @include('layouts.datagrid._table') -
- @endif + @include('campaigns.recovery._table')
+
+ @endsection diff --git a/routes/campaigns/campaign.php b/routes/campaigns/campaign.php index c3f4750627..cc789d7ea0 100644 --- a/routes/campaigns/campaign.php +++ b/routes/campaigns/campaign.php @@ -52,9 +52,6 @@ Route::get('/w/{campaign}/recovery', 'Campaign\RecoveryController@index')->name('recovery'); Route::post('/w/{campaign}/recovery', 'Campaign\RecoveryController@recover')->name('recovery.save'); -Route::get('/w/{campaign}/recovery/posts', 'Campaign\PostRecoveryController@index')->name('recovery.posts'); -Route::post('/w/{campaign}/recovery/posts', 'Campaign\PostRecoveryController@recover')->name('recovery.save.posts'); - // Stats Route::get('/w/{campaign}/achievements', 'Campaign\AchievementController@index')->name('stats'); From dab558196590e7a138df7c1727dbd0f470f5f9a9 Mon Sep 17 00:00:00 2001 From: spitfire305 Date: Thu, 22 Aug 2024 16:47:46 +0000 Subject: [PATCH 02/12] Fix styling --- app/Http/Controllers/Campaign/RecoveryController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index 9b0d1cba8b..608859ce09 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -32,7 +32,7 @@ public function index(Campaign $campaign) $this->authorize('recover', $campaign); $elements = DB::select( - 'select id, name, deleted_at, deleted_by, "entity" as type + 'select id, name, deleted_at, deleted_by, "entity" as type from entities where deleted_at is not null and campaign_id = ' . $campaign->id . ' union all @@ -41,8 +41,7 @@ public function index(Campaign $campaign) left join entities as e on e.id = p.entity_id where p.deleted_at is not null and e.deleted_at is null and e.campaign_id = ' . $campaign->id . ' order by deleted_at DESC' - - ); + ); return view('campaigns.recovery.index', compact('elements', 'campaign')); } From 583ca1e99ea245dafbe8b77da8a9ff5caafd2389 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Wed, 28 Aug 2024 07:46:56 -0600 Subject: [PATCH 03/12] Fixed translation --- lang/en/campaigns/recovery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/campaigns/recovery.php b/lang/en/campaigns/recovery.php index d4ba1e1c02..14937edcf2 100644 --- a/lang/en/campaigns/recovery.php +++ b/lang/en/campaigns/recovery.php @@ -10,6 +10,6 @@ 'deleted_at' => 'Deleted :date' ], 'helper' => 'Deleted entities of the campaign can be recovered for up to :count days. Entities deleted while the campaign isn\'t upgraded to premium status are still recoverable once the campaign is upgraded.', - 'success_v2' => '{1} :count post or entity was recovered.|[2,*] :count posts and/or entities were recovered.', + 'success_v2' => '{1} :count element was recovered.|[2,*] :count elements were recovered.', 'title' => 'Entity Recovery', ]; From 481dba51c1163138a3b42253ed77ab5e626aad3d Mon Sep 17 00:00:00 2001 From: Spitfire Date: Thu, 22 Aug 2024 10:44:18 -0600 Subject: [PATCH 04/12] PostRecove --- .../Campaign/PostRecoveryController.php | 77 ------------------- .../Campaign/RecoveryController.php | 56 ++++++-------- lang/en/campaigns/recovery.php | 14 +--- .../views/campaigns/recovery/_table.blade.php | 23 ++++++ .../views/campaigns/recovery/index.blade.php | 36 ++------- routes/campaigns/campaign.php | 3 - 6 files changed, 59 insertions(+), 150 deletions(-) delete mode 100644 app/Http/Controllers/Campaign/PostRecoveryController.php create mode 100644 resources/views/campaigns/recovery/_table.blade.php diff --git a/app/Http/Controllers/Campaign/PostRecoveryController.php b/app/Http/Controllers/Campaign/PostRecoveryController.php deleted file mode 100644 index 806396bbef..0000000000 --- a/app/Http/Controllers/Campaign/PostRecoveryController.php +++ /dev/null @@ -1,77 +0,0 @@ -middleware('auth'); - - $this->service = $service; - } - - /** - * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\JsonResponse - * @throws \Illuminate\Auth\Access\AuthorizationException - */ - public function index(Campaign $campaign) - { - $this->authorize('recover', $campaign); - - Datagrid::layout(\App\Renderers\Layouts\Campaign\PostRecovery::class) - ->permissions(false); - - $rows = $campaign->posts()->onlyTrashed() - ->sort(request()->only(['o', 'k']), ['deleted_at' => 'DESC']) - ->whereDate('posts.deleted_at', '>=', Carbon::today()->subDays(config('entities.hard_delete_posts'))) - ->paginate(); - - // Ajax Datagrid - if (request()->ajax()) { - $html = view('layouts.datagrid._table') - ->with('rows', $rows) - ->render(); - return response()->json([ - 'success' => true, - 'html' => $html, - ]); - } - $isPost = true; - return view('campaigns.recovery.index', compact('rows', 'campaign', 'isPost')); - } - - public function recover(Request $request, Campaign $campaign) - { - if (request()->ajax()) { - return response()->json(['success' => true]); - } - if (!$campaign->boosted()) { - return redirect() - ->route('recovery', $campaign) - ->with('boosted-pitch', true) - ; - } - - try { - $count = $this->service->recover($request->get('model', [])); - return redirect() - ->route('recovery.posts', $campaign) - ->with('success', trans_choice('campaigns/recovery.posts.success', $count, ['count' => $count])); - } catch (Exception $e) { - return redirect() - ->route('recovery.posts', $campaign) - ->with('error', __('campaigns/recovery.posts.error')); - } - } -} diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index dd4a78f4e2..9b0d1cba8b 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -2,24 +2,25 @@ namespace App\Http\Controllers\Campaign; -use App\Facades\Datagrid; use App\Http\Controllers\Controller; use App\Models\Campaign; -use App\Models\Entity; -use App\Services\Entity\RecoveryService; -use Carbon\Carbon; +use App\Services\Entity\RecoveryService as EntityRecoveryService; +use App\Services\Posts\RecoveryService; use Exception; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class RecoveryController extends Controller { - protected RecoveryService $service; + protected RecoveryService $postService; + protected EntityRecoveryService $entityService; - public function __construct(RecoveryService $service) + public function __construct(RecoveryService $postService, EntityRecoveryService $entityService) { $this->middleware('auth'); - $this->service = $service; + $this->postService = $postService; + $this->entityService = $entityService; } /** @@ -30,34 +31,24 @@ public function index(Campaign $campaign) { $this->authorize('recover', $campaign); - Datagrid::layout(\App\Renderers\Layouts\Campaign\Recovery::class) - ->permissions(false); + $elements = DB::select( + 'select id, name, deleted_at, deleted_by, "entity" as type + from entities + where deleted_at is not null and campaign_id = ' . $campaign->id . ' + union all + select p.id, p.name, p.deleted_at, p.deleted_by, "post" as type + from posts as p + left join entities as e on e.id = p.entity_id + where p.deleted_at is not null and e.deleted_at is null and e.campaign_id = ' . $campaign->id . + ' order by deleted_at DESC' - $rows = Entity::onlyTrashed() - ->with('image') - ->sort(request()->only(['o', 'k']), ['deleted_at' => 'DESC']) - ->whereDate('deleted_at', '>=', Carbon::today()->subDays(config('entities.hard_delete'))) - ->paginate(); + ); - // Ajax Datagrid - if (request()->ajax()) { - $html = view('layouts.datagrid._table') - ->with('rows', $rows) - ->render(); - return response()->json([ - 'success' => true, - 'html' => $html, - ]); - } - - return view('campaigns.recovery.index', compact('rows', 'campaign')); + return view('campaigns.recovery.index', compact('elements', 'campaign')); } public function recover(Request $request, Campaign $campaign) { - if (request()->ajax()) { - return response()->json(['success' => true]); - } if (!$campaign->boosted()) { return redirect() ->route('recovery', $campaign) @@ -66,10 +57,13 @@ public function recover(Request $request, Campaign $campaign) } try { - $count = $this->service->recover($request->get('model', [])); + $countEntity = $this->entityService->recover($request->get('entity', [])); + $countPost = $this->postService->recover($request->get('post', [])); + + $count = $countEntity + $countPost; return redirect() ->route('recovery', $campaign) - ->with('success', trans_choice('campaigns/recovery.success', $count, ['count' => $count])); + ->with('success', trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])); } catch (Exception $e) { return redirect() ->route('recovery', $campaign) diff --git a/lang/en/campaigns/recovery.php b/lang/en/campaigns/recovery.php index 55ebbb7c7d..d4ba1e1c02 100644 --- a/lang/en/campaigns/recovery.php +++ b/lang/en/campaigns/recovery.php @@ -6,18 +6,10 @@ ], 'error' => 'An error occurred trying to recover entities.', 'fields' => [ - 'deleted' => 'Deleted', + 'deleted' => 'Deleted', + 'deleted_at' => 'Deleted :date' ], 'helper' => 'Deleted entities of the campaign can be recovered for up to :count days. Entities deleted while the campaign isn\'t upgraded to premium status are still recoverable once the campaign is upgraded.', - 'post-title' => 'Post Recovery', - 'posts' => [ - 'error' => 'An error occurred trying to recover posts.', - 'success' => '{1} :count post was recovered.|[2,*] :count posts were recovered.', - ], - 'success' => '{1} :count entity was recovered.|[2,*] :count entities were recovered.', + 'success_v2' => '{1} :count post or entity was recovered.|[2,*] :count posts and/or entities were recovered.', 'title' => 'Entity Recovery', - 'toggle' => [ - 'entity' => 'Switch to entity recovery', - 'post' => 'Switch to post recovery', - ], ]; diff --git a/resources/views/campaigns/recovery/_table.blade.php b/resources/views/campaigns/recovery/_table.blade.php new file mode 100644 index 0000000000..98fe82cf43 --- /dev/null +++ b/resources/views/campaigns/recovery/_table.blade.php @@ -0,0 +1,23 @@ +
+ @foreach ($elements as $element) +
+
+
+ +
+
{{ $element->name }}
+ +
+ @if ($element->type == 'entity') + {{ __('crud.fields.entity') }} + @else + {{ __('entities.post') }} + @endif +
+
+
+ {{ __('campaigns/recovery.fields.deleted_at', ['date' => \Carbon\Carbon::createFromTimeStamp(strtotime($element->deleted_at))->diffForHumans()]) }} +
+
+ @endforeach +
diff --git a/resources/views/campaigns/recovery/index.blade.php b/resources/views/campaigns/recovery/index.blade.php index f5bfc12e12..d366b8fffa 100644 --- a/resources/views/campaigns/recovery/index.blade.php +++ b/resources/views/campaigns/recovery/index.blade.php @@ -9,51 +9,31 @@ ]) @section('content') - +
@include('partials.errors')

- @if (isset($isPost)) - {{ __('campaigns/recovery.post-title') }} - @else {{ __('campaigns/recovery.title') }} - @endif

+ - @if(isset($isPost)) - - - {{ __('campaigns/recovery.toggle.entity') }} - - @else - - - {{ __('campaigns/recovery.toggle.post') }} - - @endif
@if (session()->get('boosted-pitch')) @endif - - @if(Datagrid::hasBulks()) - -
- @include('layouts.datagrid._table') -
-
- @else -
- @include('layouts.datagrid._table') -
- @endif + @include('campaigns.recovery._table')
+
+ @endsection diff --git a/routes/campaigns/campaign.php b/routes/campaigns/campaign.php index 1afee597d6..d0293240f6 100644 --- a/routes/campaigns/campaign.php +++ b/routes/campaigns/campaign.php @@ -56,9 +56,6 @@ Route::get('/w/{campaign}/recovery', 'Campaign\RecoveryController@index')->name('recovery'); Route::post('/w/{campaign}/recovery', 'Campaign\RecoveryController@recover')->name('recovery.save'); -Route::get('/w/{campaign}/recovery/posts', 'Campaign\PostRecoveryController@index')->name('recovery.posts'); -Route::post('/w/{campaign}/recovery/posts', 'Campaign\PostRecoveryController@recover')->name('recovery.save.posts'); - // Stats Route::get('/w/{campaign}/achievements', 'Campaign\AchievementController@index')->name('stats'); From 8531932c190d30a091ba4c65130443a3d36f760e Mon Sep 17 00:00:00 2001 From: spitfire305 Date: Thu, 22 Aug 2024 16:47:46 +0000 Subject: [PATCH 05/12] Fix styling --- app/Http/Controllers/Campaign/RecoveryController.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index 9b0d1cba8b..608859ce09 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -32,7 +32,7 @@ public function index(Campaign $campaign) $this->authorize('recover', $campaign); $elements = DB::select( - 'select id, name, deleted_at, deleted_by, "entity" as type + 'select id, name, deleted_at, deleted_by, "entity" as type from entities where deleted_at is not null and campaign_id = ' . $campaign->id . ' union all @@ -41,8 +41,7 @@ public function index(Campaign $campaign) left join entities as e on e.id = p.entity_id where p.deleted_at is not null and e.deleted_at is null and e.campaign_id = ' . $campaign->id . ' order by deleted_at DESC' - - ); + ); return view('campaigns.recovery.index', compact('elements', 'campaign')); } From 6d5527a08c18bac07ff32073c419f842093e6880 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Wed, 28 Aug 2024 07:46:56 -0600 Subject: [PATCH 06/12] Fixed translation --- lang/en/campaigns/recovery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/en/campaigns/recovery.php b/lang/en/campaigns/recovery.php index d4ba1e1c02..14937edcf2 100644 --- a/lang/en/campaigns/recovery.php +++ b/lang/en/campaigns/recovery.php @@ -10,6 +10,6 @@ 'deleted_at' => 'Deleted :date' ], 'helper' => 'Deleted entities of the campaign can be recovered for up to :count days. Entities deleted while the campaign isn\'t upgraded to premium status are still recoverable once the campaign is upgraded.', - 'success_v2' => '{1} :count post or entity was recovered.|[2,*] :count posts and/or entities were recovered.', + 'success_v2' => '{1} :count element was recovered.|[2,*] :count elements were recovered.', 'title' => 'Entity Recovery', ]; From 00ce3fde2463706006fae07e34552245951b90fc Mon Sep 17 00:00:00 2001 From: Spitfire Date: Mon, 2 Sep 2024 13:30:18 -0600 Subject: [PATCH 07/12] Working prototype of vue entity recovery --- .../Campaign/RecoveryController.php | 29 +- app/Services/Entity/RecoveryService.php | 26 +- app/Services/Entity/RecoverySetupService.php | 167 ++++++ app/Services/Posts/RecoveryService.php | 26 +- resources/js/recovery/Element.vue | 84 +++ resources/js/recovery/Recovery.vue | 562 ++++++++++++++++++ resources/js/recovery/recovery.js | 9 + .../views/campaigns/recovery/index.blade.php | 19 +- routes/campaigns/campaign.php | 1 + vite.config.js | 1 + 10 files changed, 888 insertions(+), 36 deletions(-) create mode 100644 app/Services/Entity/RecoverySetupService.php create mode 100644 resources/js/recovery/Element.vue create mode 100644 resources/js/recovery/Recovery.vue create mode 100644 resources/js/recovery/recovery.js diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index 608859ce09..3de01bddcb 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -6,6 +6,7 @@ use App\Models\Campaign; use App\Services\Entity\RecoveryService as EntityRecoveryService; use App\Services\Posts\RecoveryService; +use App\Services\Entity\RecoverySetupService; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -14,13 +15,15 @@ class RecoveryController extends Controller { protected RecoveryService $postService; protected EntityRecoveryService $entityService; + protected RecoverySetupService $service; - public function __construct(RecoveryService $postService, EntityRecoveryService $entityService) + + public function __construct(RecoveryService $postService, EntityRecoveryService $entityService, RecoverySetupService $recoverySetupService) { $this->middleware('auth'); - $this->postService = $postService; $this->entityService = $entityService; + $this->service = $recoverySetupService; } /** @@ -46,6 +49,19 @@ public function index(Campaign $campaign) return view('campaigns.recovery.index', compact('elements', 'campaign')); } + + public function setup(Campaign $campaign) + { + $this->authorize('recover', $campaign); + + return response()->json( + $this->service + ->user(auth()->user()) + ->campaign($campaign) + ->setup() + ); + } + public function recover(Request $request, Campaign $campaign) { if (!$campaign->boosted()) { @@ -56,10 +72,13 @@ public function recover(Request $request, Campaign $campaign) } try { - $countEntity = $this->entityService->recover($request->get('entity', [])); - $countPost = $this->postService->recover($request->get('post', [])); + $entities = $this->entityService->recover($request->get('entities', [])); + $posts = $this->postService->recover($request->get('posts', [])); + + $count = count($entities) + count($posts); + + return response()->json(['entities' => $entities, 'posts' => $posts, 'toast' => trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])]); - $count = $countEntity + $countPost; return redirect() ->route('recovery', $campaign) ->with('success', trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])); diff --git a/app/Services/Entity/RecoveryService.php b/app/Services/Entity/RecoveryService.php index e18df08719..a335581220 100644 --- a/app/Services/Entity/RecoveryService.php +++ b/app/Services/Entity/RecoveryService.php @@ -11,16 +11,18 @@ class RecoveryService /** */ - public function recover(array $ids): int + public function recover(array $ids): array { $this->count = 0; + $entities = []; foreach ($ids as $id) { - if ($this->entity($id)) { - $this->count++; + $url = $this->entity($id); + if ($url) { + $entities[$id] = $url; } } - return $this->count; + return $entities; } @@ -33,9 +35,9 @@ public function count(): int /** * Restore an entity and it's child - * @return bool if the restore worked + * @return string if the restore worked */ - protected function entity(int $id): bool + protected function entity(int $id): string { $entity = Entity::onlyTrashed()->find($id); if (!$entity) { @@ -45,14 +47,16 @@ protected function entity(int $id): bool // @phpstan-ignore-next-line $child = $entity->child()->onlyTrashed()->first(); if (!$child) { - return false; + return ''; } - $entity->restore(); + //$entity->restore(); // Refresh the child first to not re-trigger the entity creation on save - $child->refresh(); - $child->restoreQuietly(); - return true; + //$child->refresh(); + //$child->restoreQuietly(); + $this->count++; + + return $entity->url(); } } diff --git a/app/Services/Entity/RecoverySetupService.php b/app/Services/Entity/RecoverySetupService.php new file mode 100644 index 0000000000..8811831dae --- /dev/null +++ b/app/Services/Entity/RecoverySetupService.php @@ -0,0 +1,167 @@ +storage = $storage; + } + + public function term(?string $term): self + { + $this->term = $term; + return $this; + } + + public function filters(array $filters): self + { + $this->filters = $filters; + return $this; + } + + public function setup(): array + { + return [ + 'acl' => [ + 'premium' => $this->campaign->boosted() + ], + 'elements' => $this->elements(), + 'i18n' => $this->i18n(), + 'api' => [ + 'search' => route('gallery.search', [$this->campaign]), + 'recovery' => route('recovery.save', [$this->campaign]), + ], + 'upgrade' => $this->upgradeLink() + ]; + } + + public function search(): array + { + return [ + 'elements' => $this->elements() + ]; + } + + protected function elements(): array + { + $elements = DB::select( + 'select id, name, deleted_at, deleted_by, type_id, "entity" as type + from entities + where deleted_at is not null and campaign_id = ' . $this->campaign->id . ' + union all + select p.id, p.name, p.deleted_at, p.deleted_by, 0 as type_id, "post" as type + from posts as p + left join entities as e on e.id = p.entity_id + where p.deleted_at is not null and e.deleted_at is null and e.campaign_id = ' . $this->campaign->id . + ' order by deleted_at DESC' + ); + + $users = $this->campaign->users()->pluck('users.name', 'users.id')->toArray(); + foreach ($elements as $key => $element) { + $element->deleted_name = isset($users[$element->deleted_by]) ? $users[$element->deleted_by] : 'Unknown'; + $element->date = \Carbon\Carbon::createFromTimeStamp(strtotime($element->deleted_at))->diffForHumans(); + $element->position = $key; + } + return collect($elements)->map(function($x){ return (array) $x; })->toArray(); + } + + protected function i18n(): array + { + $translations = [ + '0' => __('entities.post'), + 'filters' => __('bookmarks.fields.filters'), + 'new_folder' => __('campaigns/gallery.uploader.new_folder'), + 'select' => __('crud.select'), + 'select_all' => 'Select all', + 'deselect_all' => 'Cancel selection', + 'restore' => 'Restore', + 'restore_selected' => 'Restore selected', + 'cancel' => __('crud.cancel'), + 'remove' => __('crud.remove'), + 'create' => __('crud.create'), + 'update' => __('crud.update'), + 'move' => __('crud.actions.move'), + 'home' => __('Home'), + 'load_more' => __('Load more'), + + 'recover' => 'recover', + 'newest' => 'newest first', + 'oldest' => 'oldest first', + 'type' => 'type', + + // Space + 'storage' => __('campaigns/gallery.storage.title'), + 'of' => __('campaigns/gallery.storage.of'), + 'upgrade' => __('campaigns/gallery.actions.upgrade'), + + // Files + 'details' => __('campaigns/gallery.fields.details'), + 'used_in' => __('campaigns/gallery.fields.used_in'), + 'unused' => __('campaigns/gallery.fields.unused'), + 'name' => __('crud.fields.name'), + 'delete' => __('crud.remove'), + 'save' => __('crud.save'), + 'saved' => __('gallery.file.saved'), + 'confirm' => __('crud.click_modal.confirm'), + 'visibility' => __('crud.fields.visibility'), + 'size' => __('campaigns/gallery.fields.size'), + 'file_type' => __('campaigns/gallery.fields.file_type'), + 'uploaded_by' => __('campaigns/gallery.fields.created_by'), + 'focus_point' => __('campaigns/gallery.actions.focus_point'), + 'link' => __('campaigns/gallery.fields.link'), + 'open' => __('crud.actions.open'), + 'focus_locked' => __('campaigns/gallery.focus.locked'), + 'folder' => __('campaigns/gallery.fields.folder'), + + 'change' => __('crud.actions.change'), + + // Filters + 'filter_only_unused' => __('gallery.filters.only_unused'), + + 'visibility.1' => __('crud.visibilities.all'), + 'visibility.2' => __('crud.visibilities.admin'), + 'visibility.3' => __('crud.visibilities.admin-self'), + 'visibility.4' => __('crud.visibilities.self'), + 'visibility.5' => __('crud.visibilities.members'), + ]; + + $modules = config('entities.ids'); + foreach ($modules as $name => $id) { + $moduleName = __('entities.' . $name); + if ($this->campaign->superboosted() && $this->campaign->hasModuleName($id)) { + $moduleName = $this->campaign->moduleName($id); + } + $translations[$id] = $moduleName; + } + return $translations; + } + + protected function upgradeLink(): ?string + { + if ($this->campaign->boosted()) { + return null; + } + return route('settings.premium'); + } +} diff --git a/app/Services/Posts/RecoveryService.php b/app/Services/Posts/RecoveryService.php index 79b306dc0c..6e68c7e2f3 100644 --- a/app/Services/Posts/RecoveryService.php +++ b/app/Services/Posts/RecoveryService.php @@ -20,34 +20,36 @@ class RecoveryService /** */ - public function recover(array $ids): int + public function recover(array $ids): array { - $count = 0; + $posts = []; foreach ($ids as $id) { - if ($this->post($id)) { - $count++; + $url = $this->post($id); + if ($url) { + $posts[$id] = $url; } } - return $count; + return $posts; } /** - * Restore an entity and it's child - * @return bool if the restore worked + * Restore an entity post. + * @return string if the restore worked */ - protected function post(int $id): bool + protected function post(int $id): string { /** @var ?Post $post */ $post = Post::onlyTrashed()->find($id); if (!$post) { - return false; + return ''; } if ($post->entity->deleted_at) { - return false; + return ''; } - $post->restore(); + //$post->restore(); + $this->count++; - return true; + return $post->entity->url(); } } diff --git a/resources/js/recovery/Element.vue b/resources/js/recovery/Element.vue new file mode 100644 index 0000000000..d5cf90968f --- /dev/null +++ b/resources/js/recovery/Element.vue @@ -0,0 +1,84 @@ + + + diff --git a/resources/js/recovery/Recovery.vue b/resources/js/recovery/Recovery.vue new file mode 100644 index 0000000000..e6b2378dd0 --- /dev/null +++ b/resources/js/recovery/Recovery.vue @@ -0,0 +1,562 @@ + + + diff --git a/resources/js/recovery/recovery.js b/resources/js/recovery/recovery.js new file mode 100644 index 0000000000..7403320c1e --- /dev/null +++ b/resources/js/recovery/recovery.js @@ -0,0 +1,9 @@ +import { createApp } from 'vue' +import Recovery from "./Recovery.vue" +import vClickOutside from "click-outside-vue3" + +const app = createApp({}) +app.component('recovery', Recovery) +app.use(vClickOutside) + +app.mount('#recovery'); diff --git a/resources/views/campaigns/recovery/index.blade.php b/resources/views/campaigns/recovery/index.blade.php index d366b8fffa..fbe7969c6f 100644 --- a/resources/views/campaigns/recovery/index.blade.php +++ b/resources/views/campaigns/recovery/index.blade.php @@ -9,17 +9,12 @@ ]) @section('content') -
@include('partials.errors')

- {{ __('campaigns/recovery.title') }} + {{ __('campaigns/recovery.title') }}

-
- @endsection @@ -45,3 +43,8 @@ @endsection + +@section('scripts') + @parent + @vite('resources/js/recovery/recovery.js') +@endsection diff --git a/routes/campaigns/campaign.php b/routes/campaigns/campaign.php index d0293240f6..10546ca656 100644 --- a/routes/campaigns/campaign.php +++ b/routes/campaigns/campaign.php @@ -55,6 +55,7 @@ // Recovery Route::get('/w/{campaign}/recovery', 'Campaign\RecoveryController@index')->name('recovery'); Route::post('/w/{campaign}/recovery', 'Campaign\RecoveryController@recover')->name('recovery.save'); +Route::get('/w/{campaign}/recovery-setup', 'Campaign\RecoveryController@setup')->name('recovery.setup'); // Stats Route::get('/w/{campaign}/achievements', 'Campaign\AchievementController@index')->name('stats'); diff --git a/vite.config.js b/vite.config.js index 85d2ba00d7..486a50d636 100644 --- a/vite.config.js +++ b/vite.config.js @@ -46,6 +46,7 @@ export default defineConfig({ 'resources/js/profile.js', 'resources/js/cookieconsent.js', 'resources/js/relations.js', + 'resources/js/recovery/recovery.js', 'resources/js/gallery.js', 'resources/js/gallery/gallery.js', 'resources/js/history.js', From d1cdeee7b0c58ab12f30994e3ca0f5b83f1dd31e Mon Sep 17 00:00:00 2001 From: Spitfire Date: Tue, 3 Sep 2024 13:49:15 -0600 Subject: [PATCH 08/12] Recovery menu migrated to VueJS --- .../Campaign/RecoveryController.php | 4 - app/Models/Entity.php | 4 +- app/Services/Entity/RecoveryService.php | 6 +- app/Services/Entity/RecoverySetupService.php | 75 ++--- app/Services/Posts/RecoveryService.php | 6 +- lang/en/campaigns/recovery.php | 15 +- resources/js/recovery/Element.vue | 77 ++--- resources/js/recovery/Recovery.vue | 281 +++--------------- 8 files changed, 127 insertions(+), 341 deletions(-) diff --git a/app/Http/Controllers/Campaign/RecoveryController.php b/app/Http/Controllers/Campaign/RecoveryController.php index 3de01bddcb..bd19f40da4 100644 --- a/app/Http/Controllers/Campaign/RecoveryController.php +++ b/app/Http/Controllers/Campaign/RecoveryController.php @@ -78,10 +78,6 @@ public function recover(Request $request, Campaign $campaign) $count = count($entities) + count($posts); return response()->json(['entities' => $entities, 'posts' => $posts, 'toast' => trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])]); - - return redirect() - ->route('recovery', $campaign) - ->with('success', trans_choice('campaigns/recovery.success_v2', $count, ['count' => $count])); } catch (Exception $e) { return redirect() ->route('recovery', $campaign) diff --git a/app/Models/Entity.php b/app/Models/Entity.php index 275a980aca..17f5704377 100644 --- a/app/Models/Entity.php +++ b/app/Models/Entity.php @@ -187,12 +187,12 @@ public function url(string $action = 'show', array $options = []) { $campaign = CampaignLocalization::getCampaign(); try { + $routeOptions = array_merge([$campaign, $this->entity_id], $options); if ($action == 'index') { return route($this->pluralType() . '.index', $campaign); } elseif ($action === 'show') { - return route('entities.show', [$campaign, $this]); + return route('entities.show', $routeOptions); } - $routeOptions = array_merge([$campaign, $this->entity_id], $options); return route($this->pluralType() . '.' . $action, $routeOptions); } catch (Exception $e) { return route('dashboard', $campaign); diff --git a/app/Services/Entity/RecoveryService.php b/app/Services/Entity/RecoveryService.php index a335581220..a545cb1231 100644 --- a/app/Services/Entity/RecoveryService.php +++ b/app/Services/Entity/RecoveryService.php @@ -50,11 +50,11 @@ protected function entity(int $id): string return ''; } - //$entity->restore(); + $entity->restore(); // Refresh the child first to not re-trigger the entity creation on save - //$child->refresh(); - //$child->restoreQuietly(); + $child->refresh(); + $child->restoreQuietly(); $this->count++; return $entity->url(); diff --git a/app/Services/Entity/RecoverySetupService.php b/app/Services/Entity/RecoverySetupService.php index 8811831dae..c14db6396f 100644 --- a/app/Services/Entity/RecoverySetupService.php +++ b/app/Services/Entity/RecoverySetupService.php @@ -2,13 +2,9 @@ namespace App\Services\Entity; -use App\Facades\CampaignCache; -use App\Models\Campaign; -use App\Models\Entity; use App\Services\Gallery\StorageService; use App\Traits\CampaignAware; use App\Traits\UserAware; -use Barryvdh\Reflection\DocBlock\Type\Collection; use Illuminate\Support\Facades\DB; class RecoverySetupService @@ -90,62 +86,25 @@ protected function i18n(): array { $translations = [ '0' => __('entities.post'), - 'filters' => __('bookmarks.fields.filters'), - 'new_folder' => __('campaigns/gallery.uploader.new_folder'), - 'select' => __('crud.select'), - 'select_all' => 'Select all', - 'deselect_all' => 'Cancel selection', - 'restore' => 'Restore', - 'restore_selected' => 'Restore selected', - 'cancel' => __('crud.cancel'), - 'remove' => __('crud.remove'), - 'create' => __('crud.create'), - 'update' => __('crud.update'), - 'move' => __('crud.actions.move'), - 'home' => __('Home'), - 'load_more' => __('Load more'), - - 'recover' => 'recover', - 'newest' => 'newest first', - 'oldest' => 'oldest first', - 'type' => 'type', - - // Space - 'storage' => __('campaigns/gallery.storage.title'), - 'of' => __('campaigns/gallery.storage.of'), - 'upgrade' => __('campaigns/gallery.actions.upgrade'), - - // Files - 'details' => __('campaigns/gallery.fields.details'), - 'used_in' => __('campaigns/gallery.fields.used_in'), - 'unused' => __('campaigns/gallery.fields.unused'), - 'name' => __('crud.fields.name'), - 'delete' => __('crud.remove'), - 'save' => __('crud.save'), - 'saved' => __('gallery.file.saved'), + 'order_by_newest' => __('campaigns/recovery.order.newest'), + 'order_by_oldest' => __('campaigns/recovery.order.oldest'), + 'order_by_type' => __('campaigns/recovery.order.type'), + 'select_all' => __('general.select_all'), + 'deselect_all' => __('general.deselect_all'), + 'recover' => __('campaigns/recovery.actions.recover'), + 'restore_selected' => __('campaigns/recovery.actions.recover_selected'), + 'newest' => __('campaigns/recovery.order.newest_first'), + 'oldest' => __('campaigns/recovery.order.oldest_first'), + 'type' => __('campaigns/recovery.order.type_order'), + 'premium_title' => __('callouts.premium.title'), + 'premium' => __('campaigns/recovery.premium'), + 'upgrade' => __('cookieconsent.link'), 'confirm' => __('crud.click_modal.confirm'), - 'visibility' => __('crud.fields.visibility'), - 'size' => __('campaigns/gallery.fields.size'), - 'file_type' => __('campaigns/gallery.fields.file_type'), - 'uploaded_by' => __('campaigns/gallery.fields.created_by'), - 'focus_point' => __('campaigns/gallery.actions.focus_point'), - 'link' => __('campaigns/gallery.fields.link'), - 'open' => __('crud.actions.open'), - 'focus_locked' => __('campaigns/gallery.focus.locked'), - 'folder' => __('campaigns/gallery.fields.folder'), - - 'change' => __('crud.actions.change'), - - // Filters - 'filter_only_unused' => __('gallery.filters.only_unused'), - - 'visibility.1' => __('crud.visibilities.all'), - 'visibility.2' => __('crud.visibilities.admin'), - 'visibility.3' => __('crud.visibilities.admin-self'), - 'visibility.4' => __('crud.visibilities.self'), - 'visibility.5' => __('crud.visibilities.members'), + 'deleted_at' => __('campaigns/recovery.fields.deleted_at', ['date' => 'placeholder', 'user' => 'placeholder']), + 'recovery_success' => __('campaigns/recovery.name_link', ['name' => 'placeholder']), + ]; - + // Modules $modules = config('entities.ids'); foreach ($modules as $name => $id) { $moduleName = __('entities.' . $name); diff --git a/app/Services/Posts/RecoveryService.php b/app/Services/Posts/RecoveryService.php index 6e68c7e2f3..e9587112b0 100644 --- a/app/Services/Posts/RecoveryService.php +++ b/app/Services/Posts/RecoveryService.php @@ -47,9 +47,9 @@ protected function post(int $id): string if ($post->entity->deleted_at) { return ''; } - //$post->restore(); + $post->restore(); $this->count++; - - return $post->entity->url(); + $options = ['#post-' . $post->id]; + return $post->entity->url('show', $options); } } diff --git a/lang/en/campaigns/recovery.php b/lang/en/campaigns/recovery.php index 14937edcf2..f9c86579dc 100644 --- a/lang/en/campaigns/recovery.php +++ b/lang/en/campaigns/recovery.php @@ -2,14 +2,25 @@ return [ 'actions' => [ - 'recover' => 'Recover', + 'recover' => 'Recover', + 'recover_selected' => 'Recover selected' ], 'error' => 'An error occurred trying to recover entities.', 'fields' => [ 'deleted' => 'Deleted', - 'deleted_at' => 'Deleted :date' + 'deleted_at' => 'Deleted :date by :user.', ], + 'name_link' => ':name was successfully recovered', 'helper' => 'Deleted entities of the campaign can be recovered for up to :count days. Entities deleted while the campaign isn\'t upgraded to premium status are still recoverable once the campaign is upgraded.', 'success_v2' => '{1} :count element was recovered.|[2,*] :count elements were recovered.', + 'premium' => 'Recovering elements is a premium campaign feature.', 'title' => 'Entity Recovery', + 'order' => [ + 'newest' => 'Order by: Newest', + 'oldest' => 'Order by: Oldest', + 'type' => 'Order by: Type', + 'newest_first' => 'Newest first', + 'oldest_first' => 'Oldest first', + 'type_order' => 'Type', + ], ]; diff --git a/resources/js/recovery/Element.vue b/resources/js/recovery/Element.vue index d5cf90968f..fb3ae7ff32 100644 --- a/resources/js/recovery/Element.vue +++ b/resources/js/recovery/Element.vue @@ -1,28 +1,29 @@ @@ -31,7 +32,7 @@ import {ref, onMounted, watch, onBeforeMount} from 'vue' import {matches} from "lodash"; -const emit = defineEmits(['select', 'recover']) +const emit = defineEmits(['recover']) const props = defineProps<{ file: Object, @@ -39,46 +40,50 @@ const props = defineProps<{ i18n: Object }>() -const restoring = ref(false) - const click = () => { - emit('select', props.file) - props.file.is_selected = !props.file.is_selected -} - -const submit = () => { - emit('select', props.file) + if (!props.file.url) { + props.file.is_selected = !props.file.is_selected + } } const fileClass = () => { - let css = 'rounded-xl shadow bg-base-100 overflow-hidden sm:w-[12rem] cursor-pointer hover:shadow-lg relative flex flex-row md:flex-col gap-2 md:gap-0'; + let css = 'rounded shadow bg-base-100 flex flex-col gap-2 p-2 hover:shadow-lg' + + if (!props.file.url) { + css = css + ' cursor-pointer' + } if (!props.file.is_selected) { return css + ' ' } + return css + ' bg-base-300' } -const trans = (key) => { +const trans = (key, replace = []) => { if (!props.i18n[key]) { console.error('Missing trans', key, props.i18n) return 'MISSING' } - return props.i18n[key] + + let translation = props.i18n[key] + replace.forEach(f => { + translation = translation.replace("placeholder", f) + }) + + return translation } const buttonClass = () => { - let css = 'btn2 btn-secondary' - if (restoring.value) { - css += ' loading btn-disabled' + let css = 'btn2 btn-default btn-sm' + if (props.file.is_recovering) { + css += ' loading btn-disabled btn-sm' } return css } const restoreElement = () => { emit('recover', props.file) - restoring.value = true } - diff --git a/resources/js/recovery/Recovery.vue b/resources/js/recovery/Recovery.vue index e6b2378dd0..1350c83eab 100644 --- a/resources/js/recovery/Recovery.vue +++ b/resources/js/recovery/Recovery.vue @@ -3,30 +3,20 @@
-
-
- -
-
-
-