Initial baseline: LaraBlog core with plugin commerce surface.
Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Http\Controllers\Api\V1\ArticleController;
|
||||
use App\Http\Controllers\Api\V1\CategoryController;
|
||||
use App\Http\Controllers\Api\V1\MetaController;
|
||||
use App\Http\Controllers\Api\V1\TagController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
| JSON API for mini-programs / third-party clients.
|
||||
| Spec: docs/api/openapi.yaml
|
||||
*/
|
||||
Route::prefix('v1')->group(function (): void {
|
||||
Route::get('/meta', [MetaController::class, 'show']);
|
||||
Route::get('/articles', [ArticleController::class, 'index']);
|
||||
Route::get('/articles/{id}', [ArticleController::class, 'show'])->whereNumber('id');
|
||||
Route::get('/categories', [CategoryController::class, 'index']);
|
||||
Route::get('/categories/{id}/articles', [CategoryController::class, 'articles'])->whereNumber('id');
|
||||
Route::get('/tags', [TagController::class, 'index']);
|
||||
Route::get('/tags/{name}/articles', [TagController::class, 'articles']);
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Artisan::command('inspire', function () {
|
||||
$this->comment(Inspiring::quote());
|
||||
})->purpose('Display an inspiring quote');
|
||||
|
||||
Schedule::command('cache:prune-stale-tags')->daily()->when(fn () => config('cache.default') === 'redis');
|
||||
Schedule::command('queue:prune-failed --hours=168')->weekly();
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\AttachmentController;
|
||||
use App\Http\Controllers\AuthController;
|
||||
use App\Http\Controllers\BlogController;
|
||||
use App\Http\Controllers\CommentController;
|
||||
use App\Http\Controllers\LegacyGoneController;
|
||||
use App\Http\Controllers\SeoController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', [BlogController::class, 'index'])->name('home');
|
||||
|
||||
Route::match(['get', 'post'], '/show-{id}.shtml', [BlogController::class, 'show'])->whereNumber('id');
|
||||
Route::match(['get', 'post'], '/show-{id}-{page}.shtml', [BlogController::class, 'show'])->whereNumber('id')->whereNumber('page');
|
||||
|
||||
Route::get('/category-{cid}.shtml', [BlogController::class, 'category'])->whereNumber('cid');
|
||||
Route::get('/category-{cid}-{page}.shtml', [BlogController::class, 'category'])->whereNumber('cid')->whereNumber('page');
|
||||
|
||||
Route::get('/archives.shtml', fn () => app(BlogController::class)->archives(request(), 'all'));
|
||||
Route::get('/archives-{date}.shtml', [BlogController::class, 'archives'])->where('date', '\d{6}');
|
||||
Route::get('/archives-{date}-{page}.shtml', [BlogController::class, 'archives'])->where('date', '\d{6}')->whereNumber('page');
|
||||
|
||||
Route::get('/tagslist.shtml', [BlogController::class, 'tagsList']);
|
||||
Route::get('/tagslist-{page}.shtml', [BlogController::class, 'tagsList'])->whereNumber('page');
|
||||
Route::get('/tag/{name}', [BlogController::class, 'tag'])->name('tag.show');
|
||||
|
||||
Route::get('/comments.shtml', [BlogController::class, 'comments']);
|
||||
Route::get('/comments-{page}.shtml', [BlogController::class, 'comments'])->whereNumber('page');
|
||||
|
||||
Route::get('/search.shtml', [BlogController::class, 'search']);
|
||||
Route::get('/search-{page}.shtml', [BlogController::class, 'search'])->whereNumber('page');
|
||||
// Legacy sablog clients POST without Laravel CSRF; forms in themes still include @csrf.
|
||||
Route::match(['get', 'post'], '/post.php', function () {
|
||||
$action = request()->input('action', request()->query('action'));
|
||||
|
||||
return match ($action) {
|
||||
'addcomment' => app(CommentController::class)->store(request()),
|
||||
'search' => app(BlogController::class)->search(request()),
|
||||
'dologin' => app(AuthController::class)->login(request()),
|
||||
'register' => app(AuthController::class)->register(request()),
|
||||
'modpro' => app(AuthController::class)->updateProfile(request()),
|
||||
'logout' => app(AuthController::class)->logout(request()),
|
||||
default => abort(404),
|
||||
};
|
||||
})->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
|
||||
Route::get('/links.shtml', [BlogController::class, 'links']);
|
||||
Route::get('/login.shtml', [AuthController::class, 'showLogin'])->name('login');
|
||||
Route::get('/reg.shtml', [AuthController::class, 'showRegister']);
|
||||
|
||||
Route::get('/rss.xml', [SeoController::class, 'rss']);
|
||||
Route::get('/rss.php', [SeoController::class, 'rss']);
|
||||
Route::get('/sitemap.xml', [SeoController::class, 'sitemap']);
|
||||
Route::get('/sitemap.php', [SeoController::class, 'sitemap']);
|
||||
Route::get('/llms.txt', [SeoController::class, 'llms']);
|
||||
Route::get('/robots.txt', [SeoController::class, 'robots']);
|
||||
|
||||
Route::get('/attachment.php', [AttachmentController::class, 'byId']);
|
||||
Route::get('/attachments/{path}', [AttachmentController::class, 'byPath'])->where('path', '.*');
|
||||
|
||||
Route::any('/tburl.php', LegacyGoneController::class)
|
||||
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
Route::any('/trackback.php', LegacyGoneController::class)
|
||||
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||
|
||||
// Old sablog PHP admin paths (do not shadow Filament /admin panel).
|
||||
Route::any('/admin/{path}.php', LegacyGoneController::class)->where('path', '.*');
|
||||
Route::any('/admincp.php', LegacyGoneController::class);
|
||||
Route::any('/wap/{path?}', LegacyGoneController::class)->where('path', '.*');
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\AuthController;
|
||||
use App\Http\Controllers\BlogController;
|
||||
use App\Settings\GeneralSettings;
|
||||
use App\Domain\Seo\SeoPresenter;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
require __DIR__.'/legacy.php';
|
||||
|
||||
Route::get('/docs/api/openapi.yaml', function () {
|
||||
$file = base_path('docs/api/openapi.yaml');
|
||||
abort_unless(is_file($file), 404);
|
||||
|
||||
return response()->file($file, ['Content-Type' => 'application/yaml; charset=UTF-8']);
|
||||
});
|
||||
|
||||
Route::get('/posts/{slug}', [BlogController::class, 'bySlug'])->where('slug', '[A-Za-z0-9\\-]+');
|
||||
|
||||
// Dev/local attachments disk public URL (ATTACHMENTS_DRIVER=local)
|
||||
Route::get('/attachments-local/{path}', function (string $path) {
|
||||
$disk = Storage::disk(config('larablog.attachments_disk', 'attachments'));
|
||||
abort_unless($disk->exists($path), 404);
|
||||
|
||||
return $disk->response($path);
|
||||
})->where('path', '.*');
|
||||
|
||||
// Fallback when public/themes/{theme} symlink is missing.
|
||||
Route::get('/themes/{theme}/{path}', function (string $theme, string $path) {
|
||||
$base = base_path('themes/'.$theme.'/assets');
|
||||
$baseReal = realpath($base);
|
||||
$file = realpath($base.'/'.$path);
|
||||
if (! $baseReal || ! $file || ! str_starts_with($file, $baseReal) || ! is_file($file)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$mime = match (strtolower(pathinfo($file, PATHINFO_EXTENSION))) {
|
||||
'css' => 'text/css; charset=UTF-8',
|
||||
'js' => 'application/javascript; charset=UTF-8',
|
||||
'mjs' => 'application/javascript; charset=UTF-8',
|
||||
'png' => 'image/png',
|
||||
'jpg', 'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'svg' => 'image/svg+xml',
|
||||
'webp' => 'image/webp',
|
||||
'woff' => 'font/woff',
|
||||
'woff2' => 'font/woff2',
|
||||
'ttf' => 'font/ttf',
|
||||
'map' => 'application/json',
|
||||
default => mime_content_type($file) ?: 'application/octet-stream',
|
||||
};
|
||||
|
||||
return response()->file($file, [
|
||||
'Content-Type' => $mime,
|
||||
'Cache-Control' => 'public, max-age=3600',
|
||||
]);
|
||||
})->where('path', '.*');
|
||||
|
||||
// /index.php is often rewritten to /; handle legacy query actions here and on /
|
||||
Route::get('/index.php', function () {
|
||||
$action = request()->query('action');
|
||||
|
||||
return match ($action) {
|
||||
'tags' => request()->filled('item')
|
||||
? redirect('/tag/'.rawurlencode((string) request()->query('item')), 301)
|
||||
: app(BlogController::class)->tagsList(),
|
||||
'login' => app(AuthController::class)->showLogin(app(GeneralSettings::class)),
|
||||
'reg' => app(AuthController::class)->showRegister(app(GeneralSettings::class)),
|
||||
'profile' => app(AuthController::class)->showProfile(app(GeneralSettings::class)),
|
||||
'links' => app(BlogController::class)->links(),
|
||||
'comments' => app(BlogController::class)->comments(),
|
||||
'tagslist' => app(BlogController::class)->tagsList(),
|
||||
'search' => app(BlogController::class)->search(request()),
|
||||
'show' => app(BlogController::class)->show(request(), (int) request()->query('id'), app(GeneralSettings::class), app(SeoPresenter::class)),
|
||||
default => app(BlogController::class)->index(request(), app(GeneralSettings::class), app(SeoPresenter::class)),
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user