Skip to content

Commit b9162f1

Browse files
committed
Merge branch 'develop' into feature/lar-109-echappement-de-code-dans-le-mail-de-notification
2 parents 22b0071 + 16efe6e commit b9162f1

File tree

147 files changed

+6879
-5171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

147 files changed

+6879
-5171
lines changed

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,8 @@ SENTRY_LARAVEL_DSN=
7676
SENTRY_TRACES_SAMPLE_RATE=
7777

7878
NOTCHPAY_PUBLIC_KEY=
79+
80+
TWITTER_CONSUMER_KEY=your-consumer-key
81+
TWITTER_CONSUMER_SECRET=your-consumer-secret
82+
TWITTER_ACCESS_TOKEN=your-accesss_token
83+
TWITTER_ACCESS_SECRET=your-access-token-secret

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
npm-debug.log
55
yarn-error.log
66
yarn.lock
7-
87
/vendor
98
composer.phar
109

app/Actions/Article/CreateArticleAction.php

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,36 @@
55
namespace App\Actions\Article;
66

77
use App\Data\CreateArticleData;
8-
use App\Gamify\Points\ArticleCreated;
98
use App\Models\Article;
10-
use App\Notifications\PostArticleToTelegram;
9+
use App\Models\User;
1110
use Carbon\Carbon;
1211
use Illuminate\Support\Facades\Auth;
1312

1413
final class CreateArticleAction
1514
{
1615
public function execute(CreateArticleData $articleData): Article
1716
{
18-
if ($articleData->publishedAt) {
19-
$articleData->publishedAt = new Carbon(
20-
time: $articleData->publishedAt,
21-
tz: config('app.timezone')
17+
if ($articleData->published_at) {
18+
$articleData->published_at = new Carbon(
19+
time: $articleData->published_at,
20+
timezone: config('app.timezone')
2221
);
2322
}
2423

24+
/** @var User $author */
25+
$author = Auth::user();
26+
2527
/** @var Article $article */
2628
$article = Article::query()->create([
2729
'title' => $articleData->title,
28-
'slug' => $articleData->title,
30+
'slug' => $articleData->slug,
2931
'body' => $articleData->body,
30-
'published_at' => $articleData->publishedAt,
31-
'submitted_at' => $articleData->submittedAt,
32-
'approved_at' => $articleData->approvedAt,
33-
'show_toc' => $articleData->showToc,
34-
'canonical_url' => $articleData->canonicalUrl,
35-
'user_id' => Auth::id(),
32+
'published_at' => $articleData->published_at,
33+
'submitted_at' => $articleData->is_draft ? null : now(),
34+
'canonical_url' => $articleData->canonical_url,
35+
'user_id' => $author->id,
3636
]);
3737

38-
if (collect($articleData->tags)->isNotEmpty()) {
39-
$article->syncTags(tags: $articleData->tags);
40-
}
41-
42-
if ($articleData->file) {
43-
$article->addMedia($articleData->file->getRealPath())
44-
->toMediaCollection('media');
45-
}
46-
47-
if ($article->isAwaitingApproval()) {
48-
// Envoi de la notification sur le channel Telegram pour la validation de l'article.
49-
Auth::user()?->notify(new PostArticleToTelegram($article));
50-
51-
session()->flash('status', __('notifications.article.created'));
52-
}
53-
54-
if (Auth::user()?->hasAnyRole(['admin', 'moderator'])) {
55-
givePoint(new ArticleCreated($article));
56-
}
57-
5838
return $article;
5939
}
6040
}

app/Console/Commands/PostArticleToTwitter.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ final class PostArticleToTwitter extends Command
1717

1818
public function handle(AnonymousNotifiable $notifiable): void
1919
{
20-
if (app()->environment('production')) {
21-
if ($article = Article::nextForSharing()) {
22-
$notifiable->notify(new PostArticleToTwitterNotification($article));
20+
if ($article = Article::nextForSharing()) {
21+
$notifiable->notify(new PostArticleToTwitterNotification($article));
2322

24-
$article->markAsShared();
25-
}
23+
$article->markAsShared();
2624
}
2725
}
2826
}

app/Data/CreateArticleData.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace App\Data;
66

77
use Carbon\Carbon;
8-
use Illuminate\Http\UploadedFile;
98
use Spatie\LaravelData\Data;
109

1110
final class CreateArticleData extends Data
@@ -14,12 +13,8 @@ public function __construct(
1413
public string $title,
1514
public string $slug,
1615
public string $body,
17-
public string $showToc,
18-
public string $canonicalUrl,
19-
public ?Carbon $publishedAt,
20-
public ?Carbon $submittedAt,
21-
public ?Carbon $approvedAt,
22-
public ?UploadedFile $file,
23-
public array $tags = [],
16+
public string $canonical_url,
17+
public ?Carbon $published_at,
18+
public bool $is_draft = false,
2419
) {}
2520
}

app/Filament/Resources/ArticleResource.php

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
namespace App\Filament\Resources;
66

77
use App\Filament\Resources\ArticleResource\Pages;
8+
use App\Gamify\Points\ArticlePublished;
89
use App\Models\Article;
910
use Filament\Resources\Resource;
11+
use Filament\Support\Enums\MaxWidth;
1012
use Filament\Tables;
1113
use Filament\Tables\Actions\Action;
1214
use Filament\Tables\Actions\ActionGroup;
1315
use Filament\Tables\Actions\BulkAction;
14-
use Filament\Tables\Columns\TextColumn;
15-
use Filament\Tables\Filters\Filter;
16+
use Filament\Tables\Enums\FiltersLayout;
1617
use Filament\Tables\Table;
1718
use Illuminate\Database\Eloquent\Builder;
1819
use Illuminate\Database\Eloquent\Collection;
@@ -23,45 +24,56 @@ final class ArticleResource extends Resource
2324

2425
protected static ?string $navigationIcon = 'heroicon-o-newspaper';
2526

27+
public static function getNavigationGroup(): ?string
28+
{
29+
return __('Contenu');
30+
}
31+
2632
public static function table(Table $table): Table
2733
{
2834
return $table
35+
->modifyQueryUsing(fn (Builder $query): Builder => $query->latest())
2936
->columns([
30-
TextColumn::make('title')
37+
Tables\Columns\SpatieMediaLibraryImageColumn::make('media')
38+
->collection('media')
39+
->label('Image'),
40+
Tables\Columns\TextColumn::make('title')
3141
->label('Titre')
32-
->sortable(),
33-
TextColumn::make('status')
34-
->getStateUsing(function ($record) {
35-
if ($record->approved_at) {
36-
return 'Approuver';
37-
} elseif ($record->declined_at) {
38-
return 'Décliner';
39-
} elseif ($record->submitted_at) {
40-
return 'Soumis';
41-
} else {
42-
return 'Brouillon';
42+
->limit(50)
43+
->tooltip(function (Tables\Columns\TextColumn $column): ?string {
44+
$state = $column->getState();
45+
46+
if (strlen($state) <= $column->getCharacterLimit()) {
47+
return null;
4348
}
49+
50+
return $state;
4451
})
45-
->colors([
46-
'success' => 'Approuver',
47-
'danger' => 'Décliner',
48-
'warning' => 'Soumis',
49-
'default' => 'Brouillon',
50-
])
51-
->badge(),
52-
TextColumn::make('submitted_at')
53-
->label('Date de soumission')
54-
->dateTime(),
55-
TextColumn::make('user.name')
52+
->sortable()
53+
->searchable(),
54+
Tables\Columns\TextColumn::make('user.name')
5655
->label('Auteur')
57-
->sortable(),
56+
->sortable()
57+
->searchable(),
58+
Tables\Columns\IconColumn::make('published_at')
59+
->label('Publié')
60+
->getStateUsing(fn (Article $record) => $record->isPublished())
61+
->boolean(),
62+
Tables\Columns\TextColumn::make('submitted_at')
63+
->label('Soumission')
64+
->placeholder('N/A')
65+
->date(),
66+
Tables\Columns\TextColumn::make('approved_at')
67+
->label('Approbation')
68+
->placeholder('N/A')
69+
->date()
70+
->toggleable(),
71+
Tables\Columns\TextColumn::make('declined_at')
72+
->label('Décliner')
73+
->placeholder('N/A')
74+
->date()
75+
->toggleable(isToggledHiddenByDefault: true),
5876
])
59-
->filters([
60-
Filter::make('submitted_at')->query(fn (Builder $query) => $query->whereNotNull('submitted_at'))->label('Soumis'),
61-
Filter::make('declined_at')->query(fn (Builder $query) => $query->whereNotNull('declined_at'))->label('Décliner'),
62-
Filter::make('approved_at')->query(fn (Builder $query) => $query->whereNotNull('approved_at'))->label('Approuver'),
63-
])
64-
6577
->actions([
6678
ActionGroup::make([
6779
Action::make('approved')
@@ -76,6 +88,8 @@ public static function table(Table $table): Table
7688
->action(function ($record): void {
7789
$record->approved_at = now();
7890
$record->save();
91+
92+
givePoint(new ArticlePublished($record));
7993
}),
8094
Action::make('declined')
8195
->visible(fn (Article $record) => $record->isAwaitingApproval())
@@ -90,23 +104,16 @@ public static function table(Table $table): Table
90104
$record->declined_at = now();
91105
$record->save();
92106
}),
93-
Tables\Actions\DeleteAction::make('delete'),
107+
Tables\Actions\Action::make('show')
108+
->icon('untitledui-eye')
109+
->url(fn (Article $record) => route('articles.show', $record))
110+
->openUrlInNewTab()
111+
->label('Afficher'),
112+
Tables\Actions\DeleteAction::make(),
94113
]),
95-
96114
])
97115
->bulkActions([
98116
Tables\Actions\BulkActionGroup::make([
99-
BulkAction::make('approved')
100-
->label('Approuver la sélection')
101-
->icon('heroicon-s-check')
102-
->color('success')
103-
->action(fn (Collection $records) => $records->each->update(['approved_at' => now()]))
104-
->deselectRecordsAfterCompletion()
105-
->requiresConfirmation()
106-
->modalIcon('heroicon-s-check')
107-
->modalHeading('Approuver')
108-
->modalSubheading('Voulez-vous vraiment approuver ces articles ?')
109-
->modalButton('Confirmer'),
110117
BulkAction::make('declined')
111118
->label('Décliner la sélection')
112119
->icon('heroicon-s-x-mark')
@@ -116,12 +123,25 @@ public static function table(Table $table): Table
116123
->requiresConfirmation()
117124
->modalIcon('heroicon-s-x-mark')
118125
->modalHeading('Décliner')
119-
->modalSubheading('Voulez-vous vraiment décliner ces articles ?')
120-
->modalButton('Confirmer'),
126+
->modalDescription('Voulez-vous vraiment décliner ces articles ?')
127+
->modalSubmitActionLabel('Confirmer'),
121128

122129
Tables\Actions\DeleteBulkAction::make(),
123130
]),
124-
]);
131+
])
132+
->filters([
133+
Tables\Filters\TernaryFilter::make('submitted_at')
134+
->label('Soumis')
135+
->nullable(),
136+
Tables\Filters\TernaryFilter::make('declined_at')
137+
->label('Décliner')
138+
->nullable(),
139+
Tables\Filters\TernaryFilter::make('approved_at')
140+
->label('Approuver')
141+
->nullable(),
142+
], layout: FiltersLayout::AboveContentCollapsible)
143+
->filtersFormColumns(4)
144+
->filtersFormWidth(MaxWidth::FourExtraLarge);
125145
}
126146

127147
public static function getPages(): array

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55
namespace App\Filament\Resources\ArticleResource\Pages;
66

77
use App\Filament\Resources\ArticleResource;
8+
use App\Models\Article;
9+
use Closure;
810
use Filament\Resources\Pages\ListRecords;
911

1012
final class ListArticles extends ListRecords
1113
{
1214
protected static string $resource = ArticleResource::class;
15+
16+
public function isTableRecordSelectable(): ?Closure
17+
{
18+
return fn (Article $record): bool => $record->isNotPublished();
19+
}
1320
}

0 commit comments

Comments
 (0)