You've already forked Atomcms-edit
f29ba72591
Security:
- Replace unescaped {!! !!} with Purify::clean() in 15+ Blade templates (XSS)
- Add rate limiting to register (3/hr), upload (10/min), SSE (6/min)
- Add max:5000 validation on article comments
- Remove duplicate exception handler callback
Hardcoded paths:
- Replace ~44 /var/www/ hardcoded paths with env() configs
- CatalogService (13), AutoDetectService (18), Commandocentrum (11), AppServiceProvider (2)
Performance:
- Add 10 missing database indexes (radio_song_requests, help_center_tickets, etc.)
- Replace Cache::flush() with targeted Cache::forget() in RadioSettings
- Cache getCachedCategories() in TicketController (N+1 fix)
- Remove redundant top-3 leaderboard query
Bug fixes:
- Fix undefined $enabled variable → $isOnline in radio index view
- Add getAvatarAttribute() accessor for non-existent avatar column
- Fix User::guilds() from wrong HasMany to HasManyThrough
Code quality:
- Replace file_get_contents with Http::timeout(10) in TraxService
- Remove commented Echo/Pusher boilerplate in bootstrap.js
- Remove TODO/FIXME comments from logo-generator templates
- Replace hardcoded Turnstile CDN URL with config()
- Restore QUEUE_CONNECTION=redis in .env.example files
133 lines
6.7 KiB
PHP
Executable File
133 lines
6.7 KiB
PHP
Executable File
<?php
|
|
|
|
use App\Http\Controllers\Api\ArticleApiController;
|
|
use App\Http\Controllers\Api\AuthController;
|
|
use App\Http\Controllers\Api\ContentApiController;
|
|
use App\Http\Controllers\Api\HelpApiController;
|
|
use App\Http\Controllers\Api\MediaApiController;
|
|
use App\Http\Controllers\Api\ShopApiController;
|
|
use App\Http\Controllers\Api\UserApiController;
|
|
use App\Http\Controllers\Community\RadioController;
|
|
use App\Http\Controllers\RadioListenerPointController;
|
|
use App\Models\Miscellaneous\WebsiteSetting;
|
|
use App\Models\RadioApiKey;
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| API Routes
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Here is where you can register API routes for your application. These
|
|
| routes are loaded by the bootstrap/app.php file and assigned
|
|
| to the "api" middleware group. Enjoy building your API!
|
|
|
|
|
*/
|
|
|
|
// Authentication routes for Next.js frontend
|
|
Route::prefix('auth')->group(function () {
|
|
Route::post('/login', [AuthController::class, 'login']);
|
|
Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum');
|
|
Route::get('/user', [AuthController::class, 'user'])->middleware('auth:sanctum');
|
|
Route::post('/register', [AuthController::class, 'register'])->middleware('throttle:register');
|
|
Route::put('/user', [AuthController::class, 'updateUser'])->middleware('auth:sanctum');
|
|
Route::put('/user/password', [AuthController::class, 'updatePassword'])->middleware('auth:sanctum');
|
|
});
|
|
|
|
// Home page data
|
|
Route::get('/home', [AuthController::class, 'home']);
|
|
|
|
// User Profile
|
|
Route::get('/user/{username}', [UserApiController::class, 'fetchUser'])->middleware('throttle:120,1');
|
|
Route::get('/profile/{username}', [UserApiController::class, 'userProfile']);
|
|
|
|
// Online Users
|
|
Route::get('/online-users', [UserApiController::class, 'onlineUsers'])->middleware('throttle:120,1');
|
|
Route::get('/online-count', [UserApiController::class, 'onlineUserCount'])->middleware('throttle:120,1')->name('api.online-count');
|
|
|
|
// Articles
|
|
Route::get('/articles', [ArticleApiController::class, 'index']);
|
|
Route::get('/articles/{slug}', [ArticleApiController::class, 'show']);
|
|
Route::post('/articles/{slug}/comment', [AuthController::class, 'articleComment'])->middleware('auth:sanctum');
|
|
|
|
// Photos
|
|
Route::get('/photos', [MediaApiController::class, 'photos']);
|
|
|
|
// Staff
|
|
Route::get('/staff', [ContentApiController::class, 'staff']);
|
|
|
|
// Shop
|
|
Route::get('/shop/packages', [ShopApiController::class, 'packages']);
|
|
Route::get('/shop/categories', [ShopApiController::class, 'categories']);
|
|
|
|
// Teams / Guilds
|
|
Route::get('/teams', [ContentApiController::class, 'teams']);
|
|
|
|
// Leaderboard
|
|
Route::get('/leaderboard', [UserApiController::class, 'leaderboard']);
|
|
|
|
// Rare Values
|
|
Route::get('/rare-values', [ContentApiController::class, 'rareValues']);
|
|
Route::get('/rare-values/categories', [ContentApiController::class, 'rareValuesCategories']);
|
|
|
|
// Settings
|
|
Route::get('/settings', [ContentApiController::class, 'settings']);
|
|
|
|
// Radio API
|
|
Route::get('/radio/current-dj', [RadioController::class, 'currentDJ'])->middleware('throttle:100,1')->name('api.radio.current-dj');
|
|
Route::get('/radio/config', [RadioController::class, 'config'])->middleware('throttle:100,1')->name('api.radio.config');
|
|
Route::get('/radio/now-playing', [RadioController::class, 'nowPlaying'])->middleware('throttle:100,1')->name('api.radio.now-playing');
|
|
Route::get('/radio/listeners', [RadioController::class, 'listeners'])->middleware('throttle:100,1')->name('api.radio.listeners');
|
|
Route::get('/radio/shouts', [RadioController::class, 'getShouts'])->middleware('throttle:100,1')->name('api.radio.shouts');
|
|
|
|
// Radio SSE (Server-Sent Events) stream
|
|
Route::get('/radio/sse', [\App\Http\Controllers\Radio\SseController::class, 'stream'])->middleware('throttle:sse')->name('api.radio.sse');
|
|
|
|
// Radio embed config
|
|
Route::get('/radio/embed/config', [\App\Http\Controllers\Radio\EmbedController::class, 'config'])->middleware('throttle:100,1')->name('api.radio.embed.config');
|
|
|
|
// Radio Settings
|
|
Route::get('/settings/radio/auto-play', function () {
|
|
$autoPlaySetting = cache()->remember('radio_auto_play_setting', 300, fn () => WebsiteSetting::where('key', 'radio_auto_play')->first());
|
|
|
|
return response()->json([
|
|
'auto_play' => $autoPlaySetting && (bool) $autoPlaySetting->value,
|
|
]);
|
|
})->middleware('throttle:100,1')->name('api.settings.radio.auto-play');
|
|
|
|
// Radio Points
|
|
Route::get('/radio/points', [RadioListenerPointController::class, 'index'])->middleware('throttle:150,1');
|
|
Route::get('/radio/points/leaderboard', [RadioListenerPointController::class, 'leaderboard'])->middleware('throttle:150,1');
|
|
Route::get('/radio/points/user', [RadioListenerPointController::class, 'userPoints'])->middleware('auth:sanctum', 'throttle:150,1');
|
|
Route::get('/radio/points/stats', [RadioListenerPointController::class, 'stats'])->middleware('throttle:150,1');
|
|
|
|
// Help Center Tickets
|
|
Route::get('/help/tickets', [HelpApiController::class, 'tickets'])->middleware('auth:sanctum');
|
|
Route::get('/help/tickets/{id}', [HelpApiController::class, 'show'])->middleware('auth:sanctum');
|
|
Route::post('/help/tickets', [HelpApiController::class, 'create'])->middleware('auth:sanctum');
|
|
Route::post('/help/tickets/{id}/reply', [HelpApiController::class, 'reply'])->middleware('auth:sanctum');
|
|
|
|
// Photo Upload
|
|
Route::post('/photos/upload', [MediaApiController::class, 'upload'])->middleware(['auth:sanctum', 'throttle:upload']);
|
|
|
|
// Shop Purchase
|
|
Route::post('/shop/packages/{packageId}/purchase', [ShopApiController::class, 'purchase'])->middleware('auth:sanctum');
|
|
|
|
// Protected Radio API (requires API key)
|
|
Route::prefix('radio/v2')->middleware(['radio.api', 'throttle:radio'])->group(function () {
|
|
Route::get('/current-dj', [RadioController::class, 'currentDJ'])->name('api.radio.v2.current-dj');
|
|
Route::get('/now-playing', [RadioController::class, 'nowPlaying'])->name('api.radio.v2.now-playing');
|
|
Route::get('/listeners', [RadioController::class, 'listeners'])->name('api.radio.v2.listeners');
|
|
Route::get('/config', [RadioController::class, 'config'])->name('api.radio.v2.config');
|
|
Route::get('/shouts', [RadioController::class, 'getShouts'])->name('api.radio.v2.shouts');
|
|
Route::get('/points', [RadioListenerPointController::class, 'index'])->name('api.radio.v2.points');
|
|
Route::get('/points/leaderboard', [RadioListenerPointController::class, 'leaderboard'])->name('api.radio.v2.points.leaderboard');
|
|
Route::get('/points/stats', [RadioListenerPointController::class, 'stats'])->name('api.radio.v2.points.stats');
|
|
Route::get('/verify', function () {
|
|
return response()->json([
|
|
'valid' => true,
|
|
'message' => 'API key is valid',
|
|
]);
|
|
})->name('api.radio.v2.verify');
|
|
});
|