fix: 🐛 restrict access to news on condition that his category is published

This commit is contained in:
Alexis Gousseau 2025-06-10 14:55:41 +02:00
parent 0df31b8a7c
commit 077de8c8ab
8 changed files with 80 additions and 21 deletions

View file

@ -3,11 +3,12 @@
namespace App\Http\Controllers\Fo;
use App\Enums\StaticPageType;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\News;
use App\Models\NewsCategory;
use App\Models\StaticPage;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
class NewsController extends Controller
{
@ -20,9 +21,10 @@ class NewsController extends Controller
{
$staticPageModel = StaticPage::getCachedStaticPage(StaticPageType::news);
$newsCategories = NewsCategory::getPublishedOrdered();
$newsViews = News::getNewsViewsByNewsCategory();
return view('fo.pages.news.index', [
'newsViews' => News::getNewsViewsByNewsCategory(),
'newsViews' => $newsViews,
'newsCategories' => $newsCategories,
'staticPageModel' => $staticPageModel
]);
@ -37,7 +39,14 @@ class NewsController extends Controller
public function show(string $slug): \Illuminate\Contracts\View\View
{
/** @var \App\Models\News|null $newsModel Current news model */
$newsModel = News::query()->where('slug', $slug)->where('published', true)->with('newsCategory')->firstOrFail();
$newsModel = News::query()
->where('slug', $slug)
->where('published', true)
->whereHas('newsCategory', function (Builder $q) {
$q->where('published', true);
})
->with('newsCategory')
->firstOrFail();
$asideNewsModels = News::query()
->orderByRaw('news_category_id = ? DESC', [$newsModel->news_category_id])
->where([

View file

@ -240,7 +240,7 @@ class News extends Model implements Sitemapable, SchemaOrgInterface
*
* @return void
*/
private static function resetCache(): void
public static function resetCache(): void
{
Cache::forget('publishedNewsWithCategories');
self::getPublishedWithNewsCategory();
@ -254,7 +254,13 @@ class News extends Model implements Sitemapable, SchemaOrgInterface
public static function getPublishedWithNewsCategory(): \Illuminate\Database\Eloquent\Collection
{
return Cache::remember('publishedNewsWithCategories', 86400, function () {
return self::query()->where('published', true)->with('newsCategory')->get();
return self::query()
->where('published', true)
->with('newsCategory')
->whereHas('newsCategory', function (Builder $q) {
$q->where('published', true);
})
->get();
});
}
@ -279,6 +285,9 @@ class News extends Model implements Sitemapable, SchemaOrgInterface
$q->where('id', $newsCategoryModel->getKey());
});
})
->whereHas('newsCategory', function (Builder $q) {
$q->where('published', true);
})
->where('published', true)
->orderByDesc('created_at')
->paginate($detect->isMobile() ? 3 : 6)
@ -359,10 +368,8 @@ class News extends Model implements Sitemapable, SchemaOrgInterface
->url(route('fo.news.show', $this))
->author($this->getOrganizationSchema())
->creator($this->getOrganizationSchema())
->copyrightYear($this->created_at->year);
if ($this->newsCategory->published) {
$schema->subjectOf($this->newsCategory->toSchemaOrg());
}
->copyrightYear($this->created_at->year)
->subjectOf($this->newsCategory->toSchemaOrg());
return $schema;
}

View file

@ -3,12 +3,12 @@
namespace App\Models;
use App\Casts\HtmlColor;
use App\Lib\Helpers\ToolboxHelper;
use App\Traits\Models\ActivityLog;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use App\Lib\Helpers\ToolboxHelper;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use Spatie\SchemaOrg\Schema;
use Uwil\SchemaOrg\Laravel\Interfaces\SchemaOrgInterface;
use Uwil\SchemaOrg\Laravel\Traits\SchemaOrgTrait;
@ -67,6 +67,7 @@ class NewsCategory extends Model implements SchemaOrgInterface
});
static::created(function () {
self::resetCache();
News::resetCache();
});
static::updating(function (self $newsCategory) {
self::assertTitleIsUnique($newsCategory->title, $newsCategory->getKey());
@ -74,9 +75,11 @@ class NewsCategory extends Model implements SchemaOrgInterface
});
static::updated(function () {
self::resetCache();
News::resetCache();
});
static::deleted(function () {
self::resetCache();
News::resetCache();
});
}

View file

@ -1,4 +1,3 @@
import type { SweetAlertResult } from "sweetalert2";
import sweetalert from "../../modules/sweetalertConfirm";
window.addEventListener("DOMContentLoaded", () => {
@ -21,8 +20,7 @@ window.addEventListener("DOMContentLoaded", () => {
"Êtes-vous sûr ?",
"Toutes les données vont être perdu",
el as HTMLFormElement,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function (response: SweetAlertResult<any>) {
function () {
(el as HTMLFormElement).submit();
},
{ icon: "warning" }
@ -30,4 +28,36 @@ window.addEventListener("DOMContentLoaded", () => {
return false;
});
}
/**
* Popup delete item.
*/
const btnElements = document.getElementsByClassName(
"confirmPublishUnpublishTS"
) as HTMLCollectionOf<Element>;
for (const element of btnElements) {
element.addEventListener("submit", function (e) {
e.preventDefault();
const el = e.target;
if (!el || !(el instanceof HTMLFormElement)) {
throw new Error(
"confirmDoneJS can only be executed on an exising form"
);
}
sweetalert.methods.confirm(
"Êtes-vous sûr ?",
"Toutes les données associées seront altérées",
el as HTMLFormElement,
function () {
(el as HTMLFormElement).submit();
},
{
icon: "warning",
confirmButtonText: "Oui, continuer",
confirmButtonColor: "btn btn-primary mx-1",
}
);
return false;
});
}
});

View file

@ -35,8 +35,8 @@ export default {
reverseButtons: true,
// * Bootstrap Styling
customClass: {
confirmButton: "btn btn-danger mx-1",
cancelButton: "btn btn-secondary mx-1",
confirmButton: options.confirmButtonColor ?? "btn btn-danger mx-1",
cancelButton: options.cancelButtonColor ?? "btn btn-secondary mx-1",
},
buttonsStyling: false,
background: getComputedStyle(document.body).getPropertyValue("--bs-body-bg"),

View file

@ -1,6 +1,7 @@
<td class="text-center align-middle">
@can('changePublished', $model)
<form action="{{ route('bo.' . $routeName . '.change-published', $model->getRouteKey()) }}" method="POST">
<form action="{{ route('bo.' . $routeName . '.change-published', $model->getRouteKey()) }}" method="POST"
@isset($classForm)class="{{ $classForm }}"@endisset>
@csrf
@method('PATCH')
<button data-bs-toggle="tooltip" type="submit"

View file

@ -24,10 +24,18 @@
<td class="text-center align-middle">
{{ str($newsModel->highlight ? 'oui' : 'non')->ucFirst() }}
</td>
@include('bo.modules.change-published-status', [
'routeName' => 'news',
'model' => $newsModel,
])
@if (!$newsModel->newsCategory->published)
<td class="text-center align-middle">
<a class="btn btn-warning" href="{{ route('bo.news_categories.show', $newsModel->newsCategory) }}">
{{ str(__(':model doit être publiée', ['model' => trans_choice('models.classes.news_category', 1)]))->ucFirst() }}
</a>
</td>
@else
@include('bo.modules.change-published-status', [
'routeName' => 'news',
'model' => $newsModel,
])
@endif
<td class="text-center align-middle">
<span class="badge text-bg-secondary">{{ $newsModel->updated_at->isoFormat('LLLL') }}</span>
</td>

View file

@ -19,6 +19,7 @@
@include('bo.modules.change-published-status', [
'routeName' => 'news_categories',
'model' => $newsCategoryModel,
'classForm' => 'confirmPublishUnpublishTS',
])
<td class="text-center align-middle">
<input type="color" value="{{ $newsCategoryModel->color }}" disabled>