Fix 401 errors for Guest PWA API endpoints: Remove global tenant middleware from bootstrap/app.php and apply only to tenant routes; add throttle:100,1 to guest routes in api.php; enhance EventPublicController with published status validation for all methods to ensure secure public access without auth.
This commit is contained in:
@@ -47,11 +47,11 @@ class EventPublicController extends BaseController
|
||||
}
|
||||
public function event(string $slug)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first([
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first([
|
||||
'id', 'slug', 'name', 'default_locale', 'created_at', 'updated_at'
|
||||
]);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
|
||||
$locale = request()->query('locale', 'de');
|
||||
@@ -88,9 +88,9 @@ class EventPublicController extends BaseController
|
||||
|
||||
public function stats(string $slug)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first(['id']);
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first(['id']);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
|
||||
$eventId = $event->id;
|
||||
@@ -127,9 +127,9 @@ class EventPublicController extends BaseController
|
||||
|
||||
public function emotions(string $slug)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first(['id']);
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first(['id']);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
|
||||
$rows = DB::table('emotions')
|
||||
@@ -176,9 +176,9 @@ class EventPublicController extends BaseController
|
||||
|
||||
public function tasks(string $slug, Request $request)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first(['id']);
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first(['id']);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
|
||||
$query = DB::table('tasks')
|
||||
@@ -260,9 +260,9 @@ class EventPublicController extends BaseController
|
||||
|
||||
public function photos(Request $request, string $slug)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first(['id']);
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first(['id']);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
$eventId = $event->id;
|
||||
|
||||
@@ -327,6 +327,7 @@ class EventPublicController extends BaseController
|
||||
public function photo(int $id)
|
||||
{
|
||||
$row = DB::table('photos')
|
||||
->join('events', 'photos.event_id', '=', 'events.id')
|
||||
->leftJoin('tasks', 'photos.task_id', '=', 'tasks.id')
|
||||
->select([
|
||||
'photos.id',
|
||||
@@ -340,9 +341,10 @@ class EventPublicController extends BaseController
|
||||
'tasks.title as task_title'
|
||||
])
|
||||
->where('photos.id', $id)
|
||||
->where('events.status', 'published')
|
||||
->first();
|
||||
if (! $row) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Photo not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Photo not found or event not public']], 404);
|
||||
}
|
||||
$row->file_path = $this->toPublicUrl((string)($row->file_path ?? ''));
|
||||
$row->thumbnail_path = $this->toPublicUrl((string)($row->thumbnail_path ?? ''));
|
||||
@@ -364,9 +366,13 @@ class EventPublicController extends BaseController
|
||||
$deviceId = 'anon';
|
||||
}
|
||||
|
||||
$photo = DB::table('photos')->where('id', $id)->first(['id', 'event_id']);
|
||||
$photo = DB::table('photos')
|
||||
->join('events', 'photos.event_id', '=', 'events.id')
|
||||
->where('photos.id', $id)
|
||||
->where('events.status', 'published')
|
||||
->first(['photos.id', 'photos.event_id']);
|
||||
if (! $photo) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Photo not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Photo not found or event not public']], 404);
|
||||
}
|
||||
|
||||
// Idempotent like per device
|
||||
@@ -401,9 +407,9 @@ class EventPublicController extends BaseController
|
||||
|
||||
public function upload(Request $request, string $slug)
|
||||
{
|
||||
$event = DB::table('events')->where('slug', $slug)->first(['id']);
|
||||
$event = DB::table('events')->where('slug', $slug)->where('status', 'published')->first(['id']);
|
||||
if (! $event) {
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found']], 404);
|
||||
return response()->json(['error' => ['code' => 'not_found', 'message' => 'Event not found or not public']], 404);
|
||||
}
|
||||
|
||||
$deviceId = (string) $request->header('X-Device-Id', 'anon');
|
||||
|
||||
@@ -25,11 +25,7 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
AddLinkHeadersForPreloadedAssets::class,
|
||||
]);
|
||||
|
||||
$middleware->api(append: [
|
||||
\App\Http\Middleware\TenantTokenGuard::class,
|
||||
\App\Http\Middleware\TenantIsolation::class,
|
||||
\App\Http\Middleware\CreditCheckMiddleware::class,
|
||||
]);
|
||||
$middleware->api(append: []);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
|
||||
2823
package-lock.json
generated
2823
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"shadcn": "^3.3.1",
|
||||
"typescript-eslint": "^8.23.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -12,19 +12,20 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
|
||||
Route::get('/oauth/authorize', [OAuthController::class, 'authorize'])->name('oauth.authorize');
|
||||
Route::post('/oauth/token', [OAuthController::class, 'token'])->name('oauth.token');
|
||||
|
||||
// Guest PWA routes (public, no auth)
|
||||
// Guest PWA routes (public, throttled, no tenant middleware)
|
||||
Route::middleware('throttle:100,1')->group(function () {
|
||||
Route::get('/events/{slug}', [EventPublicController::class, 'event'])->name('events.show');
|
||||
Route::get('/events/{slug}/stats', [EventPublicController::class, 'stats'])->name('events.stats');
|
||||
Route::get('/events/{slug}/emotions', [EventPublicController::class, 'emotions'])->name('events.emotions');
|
||||
Route::get('/events/{slug}/tasks', [EventPublicController::class, 'tasks'])->name('events.tasks');
|
||||
Route::get('/events/{slug}/photos', [EventPublicController::class, 'photos'])->name('events.photos');
|
||||
Route::get('/photos/{id}', [EventPublicController::class, 'photo'])->name('photos.show');
|
||||
|
||||
Route::post('/photos/{id}/like', [EventPublicController::class, 'like'])->name('photos.like');
|
||||
Route::post('/events/{slug}/upload', [EventPublicController::class, 'upload'])->name('events.upload');
|
||||
});
|
||||
|
||||
// Protected tenant API routes (require auth:sanctum)
|
||||
Route::middleware('auth:sanctum')->prefix('tenant')->group(function () {
|
||||
// Protected tenant API routes (require auth:sanctum + tenant middleware)
|
||||
Route::middleware(['auth:sanctum', \App\Http\Middleware\TenantTokenGuard::class, \App\Http\Middleware\TenantIsolation::class])->prefix('tenant')->group(function () {
|
||||
Route::get('me', [OAuthController::class, 'me'])->name('tenant.me');
|
||||
|
||||
// Events CRUD
|
||||
|
||||
Reference in New Issue
Block a user