Skip to content

Commit

Permalink
Merge pull request #891 from owlchester/posts-soft-deletion
Browse files Browse the repository at this point in the history
Posts can now be recovered after soft deletion
  • Loading branch information
ilestis authored Jun 7, 2024
2 parents ad9c6a0 + 61a3c2a commit 78a8e66
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 7 deletions.
11 changes: 11 additions & 0 deletions app/Console/Commands/Cleanup/CleanupTrashed.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Console\Commands\Cleanup;

use App\Models\Entity;
use App\Models\Post;
use App\Services\RecoveryService;
use App\Traits\HasJobLog;
use Carbon\Carbon;
Expand Down Expand Up @@ -68,6 +69,14 @@ public function handle()
$this->service->trash($entity);
}
});
Post::onlyTrashed()
->where('deleted_at', '<=', $delay)
->chunkById(1000, function ($posts): void {
$this->info('Chunk deleting ' . count($posts) . ' posts.');
foreach ($posts as $post) {
$this->service->trash($post);
}
});
DB::commit();
} catch (Exception $e) {
$this->error($e->getMessage());
Expand All @@ -79,6 +88,8 @@ public function handle()
$this->info('Deleted ' . $this->service->count() . ' trashed entities.');
$log .= '<br />' . 'Deleted ' . $this->service->count() . ' trashed entities.';

$this->info('Deleted ' . $this->service->countPosts() . ' trashed posts.');
$log .= '<br />' . 'Deleted ' . $this->service->countPosts() . ' trashed posts.';
$this->log($log);

return 0;
Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/Api/v1/EntityRecoveryApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct(RecoveryService $service)
*/
public function index(Campaign $campaign)
{
$this->authorize('access', $campaign);
$this->authorize('recover', $campaign);
return Resource::collection($campaign
->entities()->onlyTrashed()
->paginate());
Expand All @@ -35,7 +35,7 @@ public function index(Campaign $campaign)
*/
public function recover(Request $request, Campaign $campaign)
{
$this->authorize('access', $campaign);
$this->authorize('recover', $campaign);

if (!$campaign->boosted()) {
return response()->json(null, 204);
Expand Down
47 changes: 47 additions & 0 deletions app/Http/Controllers/Api/v1/PostRecoveryApiController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Http\Controllers\Api\v1;

use App\Models\Campaign;
use App\Http\Resources\PostResource as Resource;
use App\Http\Requests\RecoverPost as Request;
use App\Services\RecoveryService;

class PostRecoveryApiController extends ApiController
{
protected RecoveryService $service;

public function __construct(RecoveryService $service)
{
$this->middleware('auth');

$this->service = $service;
}

/**
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function index(Campaign $campaign)
{
$this->authorize('recover', $campaign);
return Resource::collection($campaign
->posts()->onlyTrashed()
->paginate());
}

/**
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function recover(Request $request, Campaign $campaign)
{
$this->authorize('recover', $campaign);

if (!$campaign->boosted()) {
return response()->json(null, 204);
}
$this->service->recoverPosts($request->posts);

return response()->json(['success' => 'Succesfully recovered deleted posts']);
}
}
76 changes: 76 additions & 0 deletions app/Http/Controllers/Campaign/PostRecoveryController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Http\Controllers\Campaign;

use App\Facades\Datagrid;
use App\Http\Controllers\Controller;
use App\Models\Campaign;
use App\Services\RecoveryService;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;

class PostRecoveryController extends Controller
{
protected RecoveryService $service;

public function __construct(RecoveryService $service)
{
$this->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'));
}

/**
* @return \Illuminate\Http\RedirectResponse
*/
public function recover(Request $request, Campaign $campaign)
{
if (!$campaign->boosted()) {
return redirect()
->route('recovery', $campaign)
->with('boosted-pitch', true)
;
}
try {
$count = $this->service->recoverPosts($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'));
}
}
}
33 changes: 33 additions & 0 deletions app/Http/Requests/RecoverPost.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RecoverPost extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
'posts' => 'array',
'posts.*' => 'distinct|exists:posts,id'
];

return $rules;
}
}
2 changes: 2 additions & 0 deletions app/Models/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* @property int $type_id
* @property int $created_by
* @property int $updated_by
* @property int $deleted_by
* @property bool|int $is_private
* @property bool|int $is_attributes_private
* @property string $tooltip
Expand All @@ -53,6 +54,7 @@
* @property Carbon $created_at
* @property Carbon $updated_at
* @property Carbon $deleted_at
*
*/
class Entity extends Model
{
Expand Down
10 changes: 10 additions & 0 deletions app/Models/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
use App\Models\Concerns\Acl;
use App\Models\Concerns\Blameable;
use App\Models\Concerns\Paginatable;
use App\Models\Concerns\SortableTrait;
use App\Traits\VisibilityIDTrait;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Laravel\Scout\Searchable;
Expand Down Expand Up @@ -49,6 +51,8 @@ class Post extends Model
use HasFactory;
use Paginatable;
use Searchable;
use SoftDeletes;
use SortableTrait;
use VisibilityIDTrait;

protected $fillable = [
Expand All @@ -65,6 +69,12 @@ class Post extends Model
'layout_id',
];

/** @var string[] Fields that can be used to order by */
protected array $sortable = [
'name',
'deleted_at',
];

/** @var array<string, string> */
public $casts = [
'settings' => 'array',
Expand Down
7 changes: 7 additions & 0 deletions app/Models/Relations/CampaignRelations.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@
use App\Models\Theme;
use App\Models\Timeline;
use App\Models\CampaignImport;
use App\Models\Post;
use App\Models\Webhook;
use App\User;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Collection;

/**
Expand Down Expand Up @@ -271,6 +273,11 @@ public function entityRelations(): HasMany
return $this->hasMany('App\Models\Relation');
}

public function posts(): HasManyThrough
{
return $this->hasManyThrough(Post::class, Entity::class);
}

/**
*/
public function plugins(): BelongsToMany
Expand Down
47 changes: 47 additions & 0 deletions app/Renderers/Layouts/Campaign/PostRecovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Renderers\Layouts\Campaign;

use App\Renderers\Layouts\Layout;

class PostRecovery extends Layout
{
/**
* Available columns
* @return array[]
*/
public function columns(): array
{
$columns = [
'name' => [
'key' => 'name',
'label' => 'crud.fields.name',
],
'deleted' => [
'key' => 'deleted_at',
'label' => 'campaigns/recovery.fields.deleted',
'class' => self::ONLY_DESKTOP,
'render' => function ($post) {
return $post->deleted_at->diffForHumans();
}
],
];

return $columns;
}

/**
* Bulk actions
*/
public function bulks(): array
{
return [
[
'action' => 'recover',
'label' => 'campaigns/recovery.actions.recover',
'icon' => 'fa-solid fa-history',
'can' => 'campaign:recover',
],
];
}
}
Loading

0 comments on commit 78a8e66

Please sign in to comment.