From 3cb98ce54241f0ea54a4bbf789208e83e309983c Mon Sep 17 00:00:00 2001 From: Benjamin Date: Mon, 29 Jun 2026 19:35:53 +0200 Subject: [PATCH 1/3] Fix download sort --- app/Livewire/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Livewire/Database.php b/app/Livewire/Database.php index dc07142..759c686 100644 --- a/app/Livewire/Database.php +++ b/app/Livewire/Database.php @@ -332,7 +332,7 @@ class Database extends Component $sortColumn = $this->sortBy; if ($sortColumn === 'total_downloads') { - $sortColumn = 'files_sum_download_count'; + return $query->orderByRaw('COALESCE(files_sum_download_count, 0) + old_download_count ' . $this->sortDir); } return $query->orderBy($sortColumn, $this->sortDir); -- 2.39.5 From 176a883633c1596600fa4de128fc7201a8ba8f3d Mon Sep 17 00:00:00 2001 From: Benjamin Date: Mon, 29 Jun 2026 19:39:10 +0200 Subject: [PATCH 2/3] Fix profile picture not aligned --- resources/css/layout/entry.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/css/layout/entry.css b/resources/css/layout/entry.css index 56db6c4..efe1d7f 100644 --- a/resources/css/layout/entry.css +++ b/resources/css/layout/entry.css @@ -220,6 +220,9 @@ overflow: hidden; background-color: var(--bg4); border: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: center; img { width: 100%; -- 2.39.5 From 22893fd957c3a6a8418e2234516c2c219f624956 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Tue, 30 Jun 2026 14:06:11 +0200 Subject: [PATCH 3/3] Final changes --- .../Controllers/ModCP/AuthorController.php | 2 +- app/Http/Controllers/ModCP/GameController.php | 2 +- .../Controllers/ModCP/GenreController.php | 2 +- .../Controllers/ModCP/LanguageController.php | 2 +- .../Controllers/ModCP/LevelController.php | 67 ++++++++++++++++ .../ModCP/ModificationsController.php | 67 ++++++++++++++++ .../Controllers/ModCP/PlatformController.php | 2 +- app/Models/Author.php | 15 ++++ app/Models/EntryReview.php | 14 +++- app/Models/Game.php | 15 ++++ app/Models/Level.php | 6 ++ app/Models/Modification.php | 7 ++ app/Models/News.php | 14 +++- app/Policies/EntryPolicy.php | 2 +- app/Services/ActivityService.php | 3 + app/View/Components/SubmitEntryStatus.php | 4 + .../views/components/gallery-field.blade.php | 2 +- .../components/main-image-field.blade.php | 2 +- resources/views/layouts/modcp.blade.php | 18 ++++- .../views/livewire/activity-logs.blade.php | 2 +- resources/views/modcp/authors.blade.php | 2 +- resources/views/modcp/deleted.blade.php | 2 +- resources/views/modcp/entries.blade.php | 2 +- resources/views/modcp/games.blade.php | 2 +- resources/views/modcp/index.blade.php | 78 ++++++++++--------- resources/views/modcp/pagination.blade.php | 34 ++++++++ resources/views/modcp/resources.blade.php | 2 +- .../views/vendor/livewire/tailwind.blade.php | 2 - routes/web.php | 4 +- 29 files changed, 316 insertions(+), 60 deletions(-) create mode 100644 app/Http/Controllers/ModCP/LevelController.php create mode 100644 app/Http/Controllers/ModCP/ModificationsController.php create mode 100644 resources/views/modcp/pagination.blade.php diff --git a/app/Http/Controllers/ModCP/AuthorController.php b/app/Http/Controllers/ModCP/AuthorController.php index 3eac649..ef3566b 100644 --- a/app/Http/Controllers/ModCP/AuthorController.php +++ b/app/Http/Controllers/ModCP/AuthorController.php @@ -19,7 +19,7 @@ class AuthorController extends Controller { $items = Author::withCount('entries') ->orderBy('name') - ->tap(fn($query) => $this->applySearch($query, ['name'])) + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) ->paginate(30) ->withQueryString(); diff --git a/app/Http/Controllers/ModCP/GameController.php b/app/Http/Controllers/ModCP/GameController.php index 6c8b9af..7c4fce7 100644 --- a/app/Http/Controllers/ModCP/GameController.php +++ b/app/Http/Controllers/ModCP/GameController.php @@ -18,7 +18,7 @@ class GameController extends Controller public function index() { $items = Game::withCount('entries')->orderBy('name') - ->tap(fn($query) => $this->applySearch($query, ['name'])) + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) ->paginate(30)->withQueryString(); $platforms = Platform::orderBy('name')->get(); $genres = Genre::orderBy('name')->get(); diff --git a/app/Http/Controllers/ModCP/GenreController.php b/app/Http/Controllers/ModCP/GenreController.php index 3364a63..63a02ba 100644 --- a/app/Http/Controllers/ModCP/GenreController.php +++ b/app/Http/Controllers/ModCP/GenreController.php @@ -18,7 +18,7 @@ class GenreController extends Controller { $items = Genre::withCount('games') ->orderBy('name') - ->tap(fn($query) => $this->applySearch($query, ['name'])) + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) ->paginate(30) ->withQueryString(); diff --git a/app/Http/Controllers/ModCP/LanguageController.php b/app/Http/Controllers/ModCP/LanguageController.php index ca000ee..7025d90 100644 --- a/app/Http/Controllers/ModCP/LanguageController.php +++ b/app/Http/Controllers/ModCP/LanguageController.php @@ -17,7 +17,7 @@ class LanguageController extends Controller { $items = Language::withCount('entries') ->orderBy('name') - ->tap(fn($query) => $this->applySearch($query, ['name'])) + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) ->paginate(30) ->withQueryString(); diff --git a/app/Http/Controllers/ModCP/LevelController.php b/app/Http/Controllers/ModCP/LevelController.php new file mode 100644 index 0000000..5531827 --- /dev/null +++ b/app/Http/Controllers/ModCP/LevelController.php @@ -0,0 +1,67 @@ +orderBy('name') + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) + ->paginate(30) + ->withQueryString(); + + return view('modcp.resources', [ + 'items' => $items, + 'title' => 'Levels', + 'singular' => 'Level', + 'storeRoute' => 'modcp.levels.store', + 'updateRoute' => 'modcp.levels.update', + 'destroyRoute' => 'modcp.levels.destroy' + ]); + } + + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255|unique:levels,name', + ]); + + Level::create([ + 'name' => trim($request->name), + 'slug' => EntryHelpers::uniqueSlug( $request->name, Level::class ), + ]); + + return back()->with('success', 'Level added.'); + } + + public function update(Request $request, Level $level) + { + $request->validate([ + 'name' => 'required|string|max:255|unique:levels,name,' . $level->id, + ]); + + $level->update([ + 'name' => trim($request->name), + 'slug' => EntryHelpers::uniqueSlug( $request->name, Level::class, $level->id ), + ]); + + return back()->with('success', 'Level updated.'); + } + + public function destroy(Level $level) + { + $level->delete(); + return back()->with('success', 'Level deleted.'); + } +} diff --git a/app/Http/Controllers/ModCP/ModificationsController.php b/app/Http/Controllers/ModCP/ModificationsController.php new file mode 100644 index 0000000..d2e9f2e --- /dev/null +++ b/app/Http/Controllers/ModCP/ModificationsController.php @@ -0,0 +1,67 @@ +orderBy('name') + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) + ->paginate(30) + ->withQueryString(); + + return view('modcp.resources', [ + 'items' => $items, + 'title' => 'Modifications', + 'singular' => 'Modification', + 'storeRoute' => 'modcp.modifications.store', + 'updateRoute' => 'modcp.modifications.update', + 'destroyRoute' => 'modcp.modifications.destroy' + ]); + } + + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:255|unique:modifications,name', + ]); + + Modification::create([ + 'name' => trim($request->name), + 'slug' => EntryHelpers::uniqueSlug( $request->name, Modification::class ), + ]); + + return back()->with('success', 'Modification added.'); + } + + public function update(Request $request, Modification $Modification) + { + $request->validate([ + 'name' => 'required|string|max:255|unique:modifications,name,' . $Modification->id, + ]); + + $Modification->update([ + 'name' => trim($request->name), + 'slug' => EntryHelpers::uniqueSlug( $request->name, Modification::class, $Modification->id ), + ]); + + return back()->with('success', 'Modification updated.'); + } + + public function destroy(Modification $Modification) + { + $Modification->delete(); + return back()->with('success', 'Modification deleted.'); + } +} diff --git a/app/Http/Controllers/ModCP/PlatformController.php b/app/Http/Controllers/ModCP/PlatformController.php index 2cffa06..410801a 100644 --- a/app/Http/Controllers/ModCP/PlatformController.php +++ b/app/Http/Controllers/ModCP/PlatformController.php @@ -18,7 +18,7 @@ class PlatformController extends Controller { $items = Platform::withCount(['games','entries']) ->orderBy('name') - ->tap(fn($query) => $this->applySearch($query, ['name'])) + ->tap(fn($query) => $this->applySearch($query, ['id','name'])) ->paginate(30) ->withQueryString(); diff --git a/app/Models/Author.php b/app/Models/Author.php index 56eacce..4cc17fc 100644 --- a/app/Models/Author.php +++ b/app/Models/Author.php @@ -7,6 +7,8 @@ use App\Services\XenforoService; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; +use Spatie\Activitylog\Models\Concerns\LogsActivity; +use Spatie\Activitylog\Support\LogOptions; /** * @property int $id @@ -32,6 +34,9 @@ use Illuminate\Database\Eloquent\Relations\HasMany; */ class Author extends Model { + + use LogsActivity; + protected $fillable = [ 'name', 'slug', 'user_id', 'website' ]; @@ -49,4 +54,14 @@ class Author extends Model return app(XenforoService::class)->getXfUser($this->user_id); } + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->useLogName('author') + ->logAll() + ->logOnlyDirty() + ->dontLogEmptyChanges() + ->setDescriptionForEvent(fn(string $eventName) => "Author {$eventName}"); + } + } diff --git a/app/Models/EntryReview.php b/app/Models/EntryReview.php index 861e48e..2b327f5 100644 --- a/app/Models/EntryReview.php +++ b/app/Models/EntryReview.php @@ -8,6 +8,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Str; use League\CommonMark\GithubFlavoredMarkdownConverter; +use Spatie\Activitylog\Models\Concerns\LogsActivity; +use Spatie\Activitylog\Support\LogOptions; /** * @property int $id @@ -41,7 +43,7 @@ use League\CommonMark\GithubFlavoredMarkdownConverter; class EntryReview extends Model { - use HasXenforoUserId, SoftDeletes; + use HasXenforoUserId, SoftDeletes, LogsActivity; protected $fillable = [ 'entry_id', 'title', 'rating', 'description', 'user_id' ]; @@ -60,4 +62,14 @@ class EntryReview extends Model return $converter->convert($this->description)->getContent(); } + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->useLogName('review') + ->logAll() + ->logOnlyDirty() + ->dontLogEmptyChanges() + ->setDescriptionForEvent(fn(string $eventName) => "Review {$eventName}"); + } + } diff --git a/app/Models/Game.php b/app/Models/Game.php index 0878b20..b7a501f 100644 --- a/app/Models/Game.php +++ b/app/Models/Game.php @@ -4,6 +4,8 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Spatie\Activitylog\Models\Concerns\LogsActivity; +use Spatie\Activitylog\Support\LogOptions; /** * @property int $id @@ -31,6 +33,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; */ class Game extends Model { + + use LogsActivity; + /** * @var string[] */ @@ -50,4 +55,14 @@ class Game extends Model { return $this->hasMany(Entry::class); } + + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->useLogName('game') + ->logAll() + ->logOnlyDirty() + ->dontLogEmptyChanges() + ->setDescriptionForEvent(fn(string $eventName) => "Game {$eventName}"); + } } diff --git a/app/Models/Level.php b/app/Models/Level.php index d205d45..4c111e5 100644 --- a/app/Models/Level.php +++ b/app/Models/Level.php @@ -3,6 +3,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * @property int $id @@ -23,4 +24,9 @@ use Illuminate\Database\Eloquent\Model; class Level extends Model { protected $fillable = ['name', 'slug']; + + public function entries(): HasMany + { + return $this->hasMany(Entry::class); + } } diff --git a/app/Models/Modification.php b/app/Models/Modification.php index d2596d1..37a43c9 100644 --- a/app/Models/Modification.php +++ b/app/Models/Modification.php @@ -3,6 +3,8 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Database\Eloquent\Relations\HasMany; /** * @property int $id @@ -23,4 +25,9 @@ use Illuminate\Database\Eloquent\Model; class Modification extends Model { protected $fillable = [ 'name', 'slug' ]; + + public function entries(): BelongsToMany + { + return $this->belongsToMany(Entry::class, 'entry_modifications'); + } } diff --git a/app/Models/News.php b/app/Models/News.php index 4eee9a6..b820561 100644 --- a/app/Models/News.php +++ b/app/Models/News.php @@ -10,6 +10,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\SoftDeletes; use League\CommonMark\GithubFlavoredMarkdownConverter; +use Spatie\Activitylog\Models\Concerns\LogsActivity; +use Spatie\Activitylog\Support\LogOptions; /** * @property int $id @@ -61,7 +63,7 @@ use League\CommonMark\GithubFlavoredMarkdownConverter; class News extends Model { - use SoftDeletes, HasGallery, HasXenforoUserId; + use SoftDeletes, HasGallery, HasXenforoUserId, LogsActivity; protected $table = 'news'; @@ -127,4 +129,14 @@ class News extends Model return EntryHelpers::getYoutubeVideoId( $this->youtube_link ); } + public function getActivitylogOptions(): LogOptions + { + return LogOptions::defaults() + ->useLogName('news') + ->logAll() + ->logOnlyDirty() + ->dontLogEmptyChanges() + ->setDescriptionForEvent(fn(string $eventName) => "News {$eventName}"); + } + } diff --git a/app/Policies/EntryPolicy.php b/app/Policies/EntryPolicy.php index 4b82c08..aad741c 100644 --- a/app/Policies/EntryPolicy.php +++ b/app/Policies/EntryPolicy.php @@ -159,7 +159,7 @@ class EntryPolicy return $user->_can('romhackplaza', 'canModerateEntries' ); } - public function moderate(User $user, Entry $entry): bool + public function moderate(User $user, ?Entry $entry = null): bool { return $user->_can('romhackplaza', 'canModerateEntries' ); } diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php index 332e94d..7a1099e 100644 --- a/app/Services/ActivityService.php +++ b/app/Services/ActivityService.php @@ -199,6 +199,9 @@ class ActivityService 'post.user_id', 'post.message' ]) ->get() + ->reject(function($post){ + return (int) $post->user_id === config('xenforo.bot_user_id'); + }) ->map($this->formatMessage(...)) ->toArray(); }); diff --git a/app/View/Components/SubmitEntryStatus.php b/app/View/Components/SubmitEntryStatus.php index 77bfb01..929217d 100644 --- a/app/View/Components/SubmitEntryStatus.php +++ b/app/View/Components/SubmitEntryStatus.php @@ -61,6 +61,10 @@ class SubmitEntryStatus extends Component } } + if( $this->isEdit && $this->entry->state === 'pending' && isset( $states['published'] ) ) { + unset( $states['published'] ); + } + return $states; } diff --git a/resources/views/components/gallery-field.blade.php b/resources/views/components/gallery-field.blade.php index dcf22f8..c1e5a8f 100644 --- a/resources/views/components/gallery-field.blade.php +++ b/resources/views/components/gallery-field.blade.php @@ -9,7 +9,7 @@ Click or drag'n drop files here.
- Accepted: PNG, JPG or WebP + Accepted: PNG, JPG, GIF or WebP
diff --git a/resources/views/components/main-image-field.blade.php b/resources/views/components/main-image-field.blade.php index 7f6f8ea..4b0eb62 100644 --- a/resources/views/components/main-image-field.blade.php +++ b/resources/views/components/main-image-field.blade.php @@ -10,7 +10,7 @@ Click or drag'n drop files here.
- Accepted: PNG, JPG or WebP + Accepted: PNG, JPG, GIF or WebP
diff --git a/resources/views/layouts/modcp.blade.php b/resources/views/layouts/modcp.blade.php index 1b173ec..3f7e0e7 100644 --- a/resources/views/layouts/modcp.blade.php +++ b/resources/views/layouts/modcp.blade.php @@ -27,10 +27,12 @@ diff --git a/resources/views/livewire/activity-logs.blade.php b/resources/views/livewire/activity-logs.blade.php index d52fd2c..0cb8c45 100644 --- a/resources/views/livewire/activity-logs.blade.php +++ b/resources/views/livewire/activity-logs.blade.php @@ -203,7 +203,7 @@
- {{ $logs->links() }} + {{ $logs->links('modcp.pagination') }}
@endif diff --git a/resources/views/modcp/authors.blade.php b/resources/views/modcp/authors.blade.php index 17708ba..4b5beb0 100644 --- a/resources/views/modcp/authors.blade.php +++ b/resources/views/modcp/authors.blade.php @@ -84,6 +84,6 @@ @endforelse - {{ $items->links() }} + {{ $items->links('modcp.pagination') }} @endsection diff --git a/resources/views/modcp/deleted.blade.php b/resources/views/modcp/deleted.blade.php index 2737c7b..9e2f92e 100644 --- a/resources/views/modcp/deleted.blade.php +++ b/resources/views/modcp/deleted.blade.php @@ -55,7 +55,7 @@ @endforeach - {{ $entries->links() }} + {{ $entries->links('modcp.pagination') }} @endif @endsection diff --git a/resources/views/modcp/entries.blade.php b/resources/views/modcp/entries.blade.php index 4089d75..18a39b5 100644 --- a/resources/views/modcp/entries.blade.php +++ b/resources/views/modcp/entries.blade.php @@ -47,6 +47,6 @@ @endforeach - {{ $entries->links() }} + {{ $entries->links( 'modcp.pagination' ) }} @endif @endsection diff --git a/resources/views/modcp/games.blade.php b/resources/views/modcp/games.blade.php index 16c6347..870b539 100644 --- a/resources/views/modcp/games.blade.php +++ b/resources/views/modcp/games.blade.php @@ -98,6 +98,6 @@ @endforelse - {{ $items->links() }} + {{ $items->links('modcp.pagination') }} @endsection diff --git a/resources/views/modcp/index.blade.php b/resources/views/modcp/index.blade.php index 1e881cb..0d820db 100644 --- a/resources/views/modcp/index.blade.php +++ b/resources/views/modcp/index.blade.php @@ -14,13 +14,15 @@ In queue - -
-
- {{ $stats['locked'] }} - Locked -
-
+ @can('moderate','\App\Models\Entry') + +
+
+ {{ $stats['locked'] }} + Locked +
+
+ @endcan @can('is-admin')
@@ -54,37 +56,39 @@ @if($recentDeleted->isNotEmpty()) -
Recently deleted
-
- @foreach($recentDeleted as $entry) -
- @endif diff --git a/resources/views/modcp/pagination.blade.php b/resources/views/modcp/pagination.blade.php new file mode 100644 index 0000000..000ac70 --- /dev/null +++ b/resources/views/modcp/pagination.blade.php @@ -0,0 +1,34 @@ + +@if ($paginator->hasPages()) +
+ + @if ($paginator->onFirstPage()) + + @else + « + @endif + + {{-- Pages --}} + @foreach ($elements as $element) + @if (is_string($element)) + + @endif + + @if (is_array($element)) + @foreach ($element as $page => $url) + {{ $page }} + @endforeach + @endif + @endforeach + + @if ($paginator->hasMorePages()) + » + @else + + @endif + +
+@endif diff --git a/resources/views/modcp/resources.blade.php b/resources/views/modcp/resources.blade.php index 37aae3d..df81626 100644 --- a/resources/views/modcp/resources.blade.php +++ b/resources/views/modcp/resources.blade.php @@ -71,6 +71,6 @@ @endforelse
- {{ $items->links() }} + {{ $items->links('modcp.pagination') }} @endsection diff --git a/resources/views/vendor/livewire/tailwind.blade.php b/resources/views/vendor/livewire/tailwind.blade.php index c08316e..49a67d7 100644 --- a/resources/views/vendor/livewire/tailwind.blade.php +++ b/resources/views/vendor/livewire/tailwind.blade.php @@ -1,7 +1,6 @@ @if ($paginator->hasPages())
- {{-- Précédent --}} @if ($paginator->onFirstPage()) @else @@ -24,7 +23,6 @@ @endif @endforeach - {{-- Suivant --}} @if ($paginator->hasMorePages()) @else diff --git a/routes/web.php b/routes/web.php index 4af9471..dc1f315 100644 --- a/routes/web.php +++ b/routes/web.php @@ -111,7 +111,7 @@ Route::name('tools.')->controller(\App\Http\Controllers\ToolsController::class)- Route::name('modcp.')->prefix('/modcp')->controller(\App\Http\Controllers\ModCPController::class)->middleware(['xf.auth','can:is-mod'])->group(function () { Route::get('/', 'index' )->name('index'); - Route::get('/locked-entries', 'locked' )->name('locked'); + Route::get('/locked-entries', 'locked' )->name('locked')->middleware('can:moderate,\App\Models\Entry'); Route::get('/draft-entries', 'draft' )->name('draft')->middleware('can:is-admin'); Route::get('/hidden-entries', 'hidden' )->name('hidden')->middleware('can:is-admin'); Route::get('/deleted-entries', 'deleted' )->name('deleted')->middleware('can:is-admin'); @@ -125,6 +125,8 @@ Route::name('modcp.')->prefix('/modcp')->controller(\App\Http\Controllers\ModCPC Route::resource('authors', \App\Http\Controllers\ModCP\AuthorController::class)->only(['index', 'store','update','destroy']); Route::resource('platforms', \App\Http\Controllers\ModCP\PlatformController::class )->middleware('can:is-admin')->only(['index', 'store','update','destroy']); Route::resource('genres', \App\Http\Controllers\ModCP\GenreController::class )->middleware('can:is-admin')->only(['index', 'store','update','destroy']); + Route::resource('levels', \App\Http\Controllers\ModCP\LevelController::class )->middleware('can:is-admin')->only(['index', 'store','update','destroy']); + Route::resource('modifications', \App\Http\Controllers\ModCP\ModificationsController::class )->middleware('can:is-admin')->only(['index', 'store','update','destroy']); }); // RedirectController -- 2.39.5