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. */ 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. */ 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. */ 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. */ 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. */ 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. */ function apiPivotResourceUri(string $name, string $related, string $foreign): string { return Str::of($name) ->append('/{') ->append($related) ->append('}/{') ->append($foreign) ->append('}') ->__toString(); } } // Admin Routes Route::apiResource('announcement', AnnouncementController::class); Route::apiResource('dump', DumpController::class); Route::apiResource('featuredtheme', FeaturedThemeController::class); Route::get('current/featuredtheme', [CurrentFeaturedThemeController::class, 'show']) ->name('featuredtheme.current.show'); Route::apiResource('feature', FeatureController::class) ->only(['index', 'show', 'update']); // Auth Routes Route::get('/me', [MyController::class, 'show'])->name('me.show'); Route::get('/me/externalprofile', [MyExternalProfileController::class, 'index'])->name('me.externalprofile.index'); Route::get('/me/notification', [MyNotificationController::class, 'index'])->name('me.notification.index'); Route::match(['put', 'patch'], '/me/notification/readall', [MyNotificationController::class, 'readall'])->name('me.notification.readall'); Route::match(['put', 'patch'], '/me/notification/{notification}/read', [MyNotificationController::class, 'read'])->name('me.notification.read'); Route::match(['put', 'patch'], '/me/notification/{notification}/unread', [MyNotificationController::class, 'unread'])->name('me.notification.unread'); Route::get('/me/playlist', [MyPlaylistController::class, 'index'])->name('me.playlist.index'); // Document Routes apiResourceWhere('page', PageController::class, ['page' => '[\pL\pM\pN\/_-]+']); // List Routes // External Routes Route::apiResource('externalprofile', ExternalProfileController::class); Route::apiResource('externalprofile.externalentry', ExternalEntryController::class) ->scoped(); // Playlist Routes Route::apiResource('playlist', PlaylistController::class); Route::apiResource('playlist.track', TrackController::class) ->scoped(); Route::get('playlist/{playlist}/forward', [PlaylistForwardController::class, 'index']) ->name('playlist.forward'); Route::get('playlist/{playlist}/track/{track}/forward', [TrackForwardController::class, 'index']) ->name('playlist.track.forward'); Route::get('playlist/{playlist}/backward', [PlaylistBackwardController::class, 'index']) ->name('playlist.backward'); Route::get('playlist/{playlist}/track/{track}/backward', [TrackBackwardController::class, 'index']) ->name('playlist.track.backward'); // Pivot Routes apiPivotResource('animeseries', 'anime', 'series', AnimeSeriesController::class); apiPivotResource('animestudio', 'anime', 'studio', AnimeStudioController::class); apiPivotResource('animethemeentryvideo', 'animethemeentry', 'video', AnimeThemeEntryVideoController::class); apiEditablePivotResource('artistmember', 'artist', 'member', ArtistMemberController::class); apiEditablePivotResource('artistsong', 'artist', 'song', ArtistSongController::class); // Wiki Routes apiResource('anime', AnimeController::class); apiResource('artist', ArtistController::class); apiResource('audio', AudioController::class); apiResource('group', GroupController::class); apiResource('image', ImageController::class); apiResource('membership', MembershipController::class); apiResource('performance', PerformanceController::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 (): void { abort(404); });