withTrashed(); Route::patch(apiResourceUri('restore', $name), [$controller, 'restore']) ->name("$name.restore") ->withTrashed(); Route::delete(apiResourceUri('forceDelete', $name), [$controller, 'forceDelete']) ->name("$name.forceDelete") ->withTrashed(); } } if (! function_exists('apiResourceWhere')) { /** * API resource route registration with soft-delete routes & custom constraints. * * @param string $name * @param string $controller * @param mixed $wheres * @return void */ function apiResourceWhere(string $name, string $controller, mixed $wheres): void { Route::apiResource($name, $controller) ->where($wheres) ->withTrashed(); Route::patch(apiResourceUri('restore', $name), [$controller, 'restore']) ->name("$name.restore") ->where($wheres) ->withTrashed(); Route::delete(apiResourceUri('forceDelete', $name), [$controller, 'forceDelete']) ->name("$name.forceDelete") ->where($wheres) ->withTrashed(); } } if (! function_exists('apiScopedResource')) { /** * API scoped resource route registration with soft-delete routes. * * @param string $name * @param string $controller * @return void */ function apiScopedResource(string $name, string $controller): void { Route::apiResource($name, $controller) ->scoped() ->withTrashed(); Route::patch(apiResourceUri('restore', $name), [$controller, 'restore']) ->name("$name.restore") ->scopeBindings() ->withTrashed(); Route::delete(apiResourceUri('forceDelete', $name), [$controller, 'forceDelete']) ->name("$name.forceDelete") ->scopeBindings() ->withTrashed(); } } if (! function_exists('apiResourceUri')) { /** * Uri for ability. * Note: Route model binding is not resolved correctly for "ability/$name/{$name}" so we need a string builder. * * @param string $ability * @param string $name * @return string */ function apiResourceUri(string $ability, string $name): string { $uri = Str::of($ability); $nameParts = Str::of($name)->explode('.'); foreach ($nameParts as $namePart) { $uri = $uri->append('/') ->append($namePart) ->append('/{') ->append($namePart) ->append('}'); } return $uri->toString(); } } if (! function_exists('apiPivotResource')) { /** * API pivot resource route registration. * * @param string $name * @param string $related * @param string $foreign * @param string $controller * @return void */ function apiPivotResource(string $name, string $related, string $foreign, string $controller): void { Route::get($name, [$controller, 'index'])->name("$name.index"); Route::post(apiPivotResourceUri($name, $related, $foreign), [$controller, 'store'])->name("$name.store"); Route::get(apiPivotResourceUri($name, $related, $foreign), [$controller, 'show'])->name("$name.show"); Route::delete(apiPivotResourceUri($name, $related, $foreign), [$controller, 'destroy'])->name("$name.destroy"); } } if (! function_exists('apiEditablePivotResource')) { /** * API pivot resource route registration with update action. * * @param string $name * @param string $related * @param string $foreign * @param string $controller * @return void */ function apiEditablePivotResource(string $name, string $related, string $foreign, string $controller): void { apiPivotResource($name, $related, $foreign, $controller); Route::match(['put', 'patch'], apiPivotResourceUri($name, $related, $foreign), [$controller, 'update'])->name("$name.update"); } } if (! function_exists('apiPivotResourceUri')) { /** * Uri for ability. * Note: Route model binding is not resolved correctly for "$name/{$related}/{$foreign}" so we need a string builder. * * @param string $name * @param string $related * @param string $foreign * @return string */ function apiPivotResourceUri(string $name, string $related, string $foreign): string { return Str::of($name) ->append('/{') ->append($related) ->append('}/{') ->append($foreign) ->append('}') ->toString(); } } // Admin Routes apiResource('announcement', AnnouncementController::class); apiResource('dump', DumpController::class); // Auth Routes Route::get('/me', [MyController::class, 'show'])->name('me.show'); Route::get('/me/playlist', [MyPlaylistController::class, 'index'])->name('me.playlist.index'); // Billing Routes apiResource('balance', BalanceController::class); apiResource('transaction', TransactionController::class); Route::get('transparency', [TransparencyController::class, 'show'])->name('transparency.show'); // Config Routes Route::get('config/flags', [FlagsController::class, 'show'])->name('config.flags.show'); Route::get('config/wiki', [WikiController::class, 'show'])->name('config.wiki.show'); // Document Routes apiResourceWhere('page', PageController::class, ['page' => '[\pL\pM\pN\/_-]+']); // List Routes apiResource('playlist', PlaylistController::class); apiScopedResource('playlist.track', TrackController::class); Route::get('playlist/{playlist}/forward', [PlaylistForwardController::class, 'index']) ->withTrashed() ->name('playlist.forward'); Route::get('playlist/{playlist}/track/{track}/forward', [TrackForwardController::class, 'index']) ->withTrashed() ->name('playlist.track.forward'); Route::get('playlist/{playlist}/backward', [PlaylistBackwardController::class, 'index']) ->withTrashed() ->name('playlist.backward'); Route::get('playlist/{playlist}/track/{track}/backward', [TrackBackwardController::class, 'index']) ->withTrashed() ->name('playlist.track.backward'); // Pivot Routes apiPivotResource('animeimage', 'anime', 'image', AnimeImageController::class); apiEditablePivotResource('animeresource', 'anime', 'resource', AnimeResourceController::class); apiPivotResource('animeseries', 'anime', 'series', AnimeSeriesController::class); apiPivotResource('animestudio', 'anime', 'studio', AnimeStudioController::class); apiPivotResource('animethemeentryvideo', 'animethemeentry', 'video', AnimeThemeEntryVideoController::class); apiPivotResource('artistimage', 'artist', 'image', ArtistImageController::class); apiEditablePivotResource('artistmember', 'artist', 'member', ArtistMemberController::class); apiEditablePivotResource('artistresource', 'artist', 'resource', ArtistResourceController::class); apiPivotResource('playlistimage', 'playlist', 'image', PlaylistImageController::class); apiPivotResource('studioimage', 'studio', 'image', StudioImageController::class); apiEditablePivotResource('studioresource', 'studio', 'resource', StudioResourceController::class); apiEditablePivotResource('artistsong', 'artist', 'song', ArtistSongController::class); // Wiki Routes apiResource('anime', AnimeController::class); apiResource('artist', ArtistController::class); apiResource('audio', AudioController::class); apiResource('image', ImageController::class); apiResource('resource', ExternalResourceController::class); Route::get('search', [SearchController::class, 'show'])->name('search.show'); apiResource('series', SeriesController::class); apiResource('song', SongController::class); apiResource('studio', StudioController::class); apiResource('video', VideoController::class); // Anime Routes apiResource('animesynonym', SynonymController::class); apiResource('animetheme', ThemeController::class); Route::get('animeyear', [YearController::class, 'index'])->name('animeyear.index'); Route::get('animeyear/{year}', [YearController::class, 'show'])->name('animeyear.show'); // Anime Theme Routes apiResource('animethemeentry', EntryController::class); // Video Routes apiResource('videoscript', ScriptController::class); Route::fallback(function () { abort(404); });