Skip to content

Commit 49c956a

Browse files
authored
feat: (LAR-105) create TransfertDiscutionToThreadAction file (#228)
Créateur qui change la discussion en thread Création du thread avec les informations de la discussion Transférer des réponses de la discussion en réponse du thread Envoyer une notification mail à tous les utilisateurs qui ont répondu pour leur dire que la discussion est devenu un sujet de forum Suppression de la discussion Admin qui change la discussion en thread Effectue les mêmes action que le créateur Envoie un mail au créateur pour lui annoncer que la discussion est devenu un sujet de forum
2 parents 03fa3ee + b14aaea commit 49c956a

33 files changed

+399
-23
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Actions\Discussion;
6+
7+
use App\Models\Discussion;
8+
use App\Models\Thread;
9+
use Illuminate\Support\Facades\DB;
10+
11+
final class ConvertDiscussionToThreadAction
12+
{
13+
public function execute(Discussion $discussion): Thread
14+
{
15+
return DB::transaction(function () use ($discussion) {
16+
$thread = Thread::create([
17+
'title' => $discussion->title,
18+
'slug' => $discussion->slug,
19+
'body' => $discussion->body,
20+
'user_id' => $discussion->user_id,
21+
'last_posted_at' => null,
22+
]);
23+
24+
$discussion->replies()->update([
25+
'replyable_type' => 'thread',
26+
'replyable_id' => $thread->id,
27+
]);
28+
29+
$discussion->delete();
30+
31+
app(NotifyUsersOfThreadConversion::class)->execute($thread);
32+
33+
return $thread;
34+
});
35+
}
36+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Actions\Discussion;
6+
7+
use App\Models\Thread;
8+
use App\Models\User;
9+
use App\Notifications\ThreadConvertedByAdmin;
10+
use App\Notifications\ThreadConvertedByCreator;
11+
use Illuminate\Support\Facades\Auth;
12+
13+
final class NotifyUsersOfThreadConversion
14+
{
15+
public function execute(Thread $thread): void
16+
{
17+
$usersToNotify = $thread->replies()->pluck('user_id')->unique()->toArray();
18+
19+
User::whereIn('id', $usersToNotify)->get()->each->notify(new ThreadConvertedByCreator($thread));
20+
21+
if (Auth::check() && Auth::user()->isAdmin()) {
22+
$thread->user->notify(new ThreadConvertedByAdmin($thread));
23+
}
24+
}
25+
}

app/Filament/Resources/ArticleResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class ArticleResource extends Resource
2525

2626
protected static ?string $navigationIcon = 'heroicon-o-newspaper';
2727

28-
public static function getNavigationGroup(): ?string
28+
public static function getNavigationGroup(): string
2929
{
3030
return __('Contenu');
3131
}

app/Filament/Resources/ArticleResource/Pages/ListArticles.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ final class ListArticles extends ListRecords
1313
{
1414
protected static string $resource = ArticleResource::class;
1515

16-
public function isTableRecordSelectable(): ?Closure
16+
public function isTableRecordSelectable(): Closure
1717
{
1818
return fn (Article $record): bool => $record->isNotPublished();
1919
}

app/Filament/Resources/ChannelResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ final class ChannelResource extends Resource
2323

2424
protected static ?string $navigationIcon = 'untitledui-git-branch';
2525

26-
public static function getNavigationGroup(): ?string
26+
public static function getNavigationGroup(): string
2727
{
2828
return __('Forum');
2929
}

app/Filament/Resources/DiscussionResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ final class DiscussionResource extends Resource
1818

1919
protected static ?string $navigationIcon = 'untitledui-message-chat-square';
2020

21-
public static function getNavigationGroup(): ?string
21+
public static function getNavigationGroup(): string
2222
{
2323
return __('Contenu');
2424
}

app/Filament/Resources/TagResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class TagResource extends Resource
2020

2121
protected static ?string $navigationIcon = 'untitledui-tag-03';
2222

23-
public static function getNavigationGroup(): ?string
23+
public static function getNavigationGroup(): string
2424
{
2525
return __('Contenu');
2626
}

app/Filament/Resources/UserResource.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ final class UserResource extends Resource
2323

2424
protected static ?string $navigationIcon = 'untitledui-users-02';
2525

26-
public static function getNavigationGroup(): ?string
26+
public static function getNavigationGroup(): string
2727
{
2828
return __('Management');
2929
}

app/Livewire/Components/Forum/ReplyForm.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function open(?int $replyId = null): void
4141
{
4242
$this->reply = Reply::query()->find($replyId);
4343

44-
$this->form->fill(['body' => $this->reply?->body ?? '']);
44+
$this->form->fill(['body' => $this->reply->body ?? '']);
4545

4646
$this->show = true;
4747
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Livewire\Modals;
6+
7+
use App\Actions\Discussion\ConvertDiscussionToThreadAction;
8+
use App\Models\Discussion;
9+
use Illuminate\Contracts\View\View;
10+
use LivewireUI\Modal\ModalComponent;
11+
12+
final class ConvertDiscussion extends ModalComponent
13+
{
14+
public int $discussionId;
15+
16+
public function save(): void
17+
{
18+
/** @var Discussion $discussion */
19+
$discussion = Discussion::query()->findOrFail($this->discussionId);
20+
21+
$this->authorize('convertedToThread', $discussion);
22+
23+
$thread = app(ConvertDiscussionToThreadAction::class)->execute($discussion);
24+
25+
$this->redirectRoute('forum.show', $thread, navigate: true);
26+
}
27+
28+
public function render(): View
29+
{
30+
return view('livewire.modals.convert-discussion');
31+
}
32+
}

app/Livewire/Modals/Unsplash.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ public static function modalMaxWidth(): string
2020

2121
public function render(): View
2222
{
23-
return view('livewire.modals.unsplash');
23+
return view('livewire.modals.unsplash'); // @phpstan-ignore-line
2424
}
2525
}

app/Mail/NewReplyEmail.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ public function __construct(
2121

2222
public function build(): self
2323
{
24-
// @phpstan-ignore-next-line
2524
return $this->subject("Re: {$this->reply->replyAble->subject()}")
2625
->markdown('emails.new_reply');
2726
}

app/Models/Discussion.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ final class Discussion extends Model implements ReactableInterface, ReplyInterfa
7171
];
7272

7373
protected $appends = [
74+
// @phpstan-ignore-next-line
7475
'count_all_replies_with_child',
7576
];
7677

app/Models/User.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ public function getFilamentAvatarUrl(): ?string
185185
}
186186

187187
/**
188-
* @return array{name: string, username: string, picture: string}
188+
* @return array{name: string, username: string, picture: string|null}
189189
*/
190190
public function profile(): array
191191
{
@@ -345,6 +345,7 @@ public function hasPassword(): bool
345345
{
346346
$password = $this->getAuthPassword();
347347

348+
// @phpstan-ignore-next-line
348349
return $password !== '' && $password !== null;
349350
}
350351

@@ -384,12 +385,12 @@ public function countReplies(): int
384385

385386
public function countSolutions(): int
386387
{
387-
return $this->replyAble()->isSolution()->count();
388+
return $this->replyAble()->isSolution()->count(); // @phpstan-ignore-line
388389
}
389390

390391
public function countArticles(): int
391392
{
392-
return $this->articles()->approved()->count();
393+
return $this->articles()->approved()->count(); // @phpstan-ignore-line
393394
}
394395

395396
public function countDiscussions(): int
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Notifications;
6+
7+
use App\Models\Thread;
8+
use Illuminate\Bus\Queueable;
9+
use Illuminate\Notifications\Messages\MailMessage;
10+
use Illuminate\Notifications\Notification;
11+
12+
final class ThreadConvertedByAdmin extends Notification
13+
{
14+
use Queueable;
15+
16+
public function __construct(public Thread $thread) {}
17+
18+
/**
19+
* Get the notification's delivery channels.
20+
*
21+
* @return array<int, string>
22+
*/
23+
public function via(object $notifiable): array
24+
{
25+
return ['mail'];
26+
}
27+
28+
/**
29+
* Get the mail representation of the notification.
30+
*/
31+
public function toMail(object $notifiable): MailMessage
32+
{
33+
return (new MailMessage)
34+
->subject(__('pages/discussion.converted_by_admin.subject'))
35+
->greeting(__('pages/discussion.converted_by_admin.greeting'))
36+
->line(__('pages/discussion.converted_by_admin.converted_line'))
37+
->line(__('pages/discussion.converted_by_admin.thread_title').$this->thread->title)
38+
->action(__('pages/discussion.converted_by_admin.action_text'), route('forum.show', $this->thread))
39+
->line(__('pages/discussion.converted_by_admin.admin_action_line'));
40+
}
41+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Notifications;
6+
7+
use App\Models\Thread;
8+
use Illuminate\Bus\Queueable;
9+
use Illuminate\Notifications\Messages\MailMessage;
10+
use Illuminate\Notifications\Notification;
11+
12+
final class ThreadConvertedByCreator extends Notification
13+
{
14+
use Queueable;
15+
16+
public function __construct(public Thread $thread) {}
17+
18+
/**
19+
* Get the notification's delivery channels.
20+
*
21+
* @return array<int, string>
22+
*/
23+
public function via(object $notifiable): array
24+
{
25+
return ['mail'];
26+
}
27+
28+
/**
29+
* Get the mail representation of the notification.
30+
*/
31+
public function toMail(object $notifiable): MailMessage
32+
{
33+
return (new MailMessage)
34+
->subject(__('pages/discussion.converted_by_creator'))
35+
->line(__('pages/discussion.converted_by_creator.converted_line'))
36+
->line(__('pages/discussion.converted_by_creator.thread_title').$this->thread->title)
37+
->action(__('pages/discussion.converted_by_creator.action_text'), route('forum.show', $this->thread))
38+
->line(__('pages/discussion.converted_by_creator.thank_you_line'));
39+
}
40+
}

app/Policies/DiscussionPolicy.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ public function report(User $user, Discussion $discussion): bool
5656
{
5757
return $user->hasVerifiedEmail() && ! $discussion->isAuthoredBy($user);
5858
}
59+
60+
public function convertedToThread(User $user, Discussion $discussion): bool
61+
{
62+
return $discussion->isAuthoredBy($user) || $user->isAdmin();
63+
}
5964
}

app/Policies/NotificationPolicy.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ final class NotificationPolicy
1616

1717
public function markAsRead(User $user, DatabaseNotification $notification): bool
1818
{
19-
return $notification->notifiable->is($user); // @phpstan-ignore-line
19+
return $notification->notifiable->is($user);
2020
}
2121
}

app/Spotlight/Article.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class Article extends SpotlightCommand
2020

2121
protected array $synonyms = [];
2222

23-
public function dependencies(): ?SpotlightCommandDependencies
23+
public function dependencies(): SpotlightCommandDependencies
2424
{
2525
return SpotlightCommandDependencies::collection()
2626
->add(

app/Spotlight/Discussion.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class Discussion extends SpotlightCommand
2020

2121
protected array $synonyms = [];
2222

23-
public function dependencies(): ?SpotlightCommandDependencies
23+
public function dependencies(): SpotlightCommandDependencies
2424
{
2525
return SpotlightCommandDependencies::collection()
2626
->add(

app/Spotlight/Sujet.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class Sujet extends SpotlightCommand
2525
'thread',
2626
];
2727

28-
public function dependencies(): ?SpotlightCommandDependencies
28+
public function dependencies(): SpotlightCommandDependencies
2929
{
3030
return SpotlightCommandDependencies::collection()
3131
->add(

app/Spotlight/User.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class User extends SpotlightCommand
2020

2121
protected array $synonyms = [];
2222

23-
public function dependencies(): ?SpotlightCommandDependencies
23+
public function dependencies(): SpotlightCommandDependencies
2424
{
2525
return SpotlightCommandDependencies::collection()
2626
->add(

app/Traits/HasReplies.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function isConversationOld(): bool
5454
$sixMonthsAgo = now()->subMonths(6);
5555

5656
if ($reply = $this->replies()->latest()->first()) {
57-
/** @var $reply Reply */
57+
/** @var Reply $reply */
5858
return $reply->created_at->lt($sixMonthsAgo);
5959
}
6060

app/Traits/HasSocialite.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Laravel\Socialite\Contracts\User;
99
use Laravel\Socialite\Facades\Socialite;
1010

11+
/**
12+
* @phpstan-ignore trait.unused
13+
*/
1114
trait HasSocialite
1215
{
1316
/**

app/Traits/UserResponse.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use App\Http\Resources\EnterpriseResource;
99
use App\Models\User;
1010

11+
/**
12+
* @phpstan-ignore trait.unused
13+
*/
1114
trait UserResponse
1215
{
1316
/**

lang/en/actions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
'save' => 'Save',
1313
'ban' => 'Ban',
1414
'unban' => 'Cancel ban',
15+
'confirm' => 'Confirm',
1516

1617
];

0 commit comments

Comments
 (0)