ifnex/04_Laravel/routes/api.php
Kazem Alghasi 8cf407553b feat(security): implement secure file storage and shipment access control
Introduce a 'secure' filesystem disk to prevent public access to sensitive
commitment form uploads. Files are now stored in a non-public directory
and served via a protected controller method that validates user ownership.

Additionally, implement shipment authorization policies to ensure users
can only access PDF documents (AWB, invoice, labels) belonging to their
own orders.

Other changes:
- Add production environment check for Zarinpal gateway configuration
  to prevent accidental use of sandbox credentials.
- Move discount code and commitment form routes under authentication
  middleware for improved security.
- Add `ShipmentPolicy` to handle resource authorization.
2026-10-01 03:34:28 +03:30

171 lines
10 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Http\Controllers\Api\CustomerFinancialController;
use App\Http\Controllers\Api\CommitmentFormController;
use App\Http\Controllers\Api\MobileVerificationController;
use App\Http\Controllers\Api\Customer\CustomerOrderController;
use App\Http\Controllers\Api\DiscountCodeController;
use App\Http\Controllers\Api\MockGatewayController;
use App\Http\Controllers\Api\PaymentController;
use App\Http\Controllers\Api\PricingController;
use App\Http\Controllers\Api\StaffOrderController;
use App\Http\Controllers\Api\TrackController;
use App\Http\Controllers\Api\WalletController;
use App\Http\Middleware\ApiKeyMiddleware;
use App\Http\Middleware\StaffApiMiddleware;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\AuthController;
use App\Http\Controllers\Api\BridgeAuthController;
use App\Http\Controllers\ShipmentPdfController;
// ══════════════════════════════════════════════════════════════
// Bridge Auth API (فقط برای پلاگین وردپرس - با API Key محافظت می‌شود)
// ══════════════════════════════════════════════════════════════
Route::post('/v1/bridge/login', [BridgeAuthController::class, 'login']); // Login
// ══════════════════════════════════════════════════════════════
// API عمومی با API Key
// ══════════════════════════════════════════════════════════════
Route::middleware([ApiKeyMiddleware::class])->prefix('v1')->group(function () {
Route::get('/track/{awb_no}', [TrackController::class, 'show']);
});
// ══════════════════════════════════════════════════════════════
// API عمومی (بدون نیاز به احراز هویت)
// ══════════════════════════════════════════════════════════════
Route::prefix('v1')->group(function () {
Route::get('/countries', [CustomerOrderController::class, 'countries']);
});
// ══════════════════════════════════════════════════════════════
// Auth API (عمومی - برای دریافت توکن)
// ══════════════════════════════════════════════════════════════
Route::post('/v1/auth/login', [AuthController::class, 'login']);
Route::middleware(['auth:sanctum'])->post('/v1/auth/logout', [AuthController::class, 'logout']);
// ══════════════════════════════════════════════════════════════
// API برای کاربران لاگین‌شده (با Sanctum / Bearer Token)
// ══════════════════════════════════════════════════════════════
Route::middleware(['auth:sanctum'])->prefix('v1')->group(function () {
// ─── Wallet API (کاربر عادی) ───
Route::get('/wallet/balance', [WalletController::class, 'balance']);
Route::get('/wallet/transactions', [WalletController::class, 'transactions']);
// ─── Payment API ───
Route::post('/payment/redirect', [PaymentController::class, 'redirectToGateway']);
Route::get('/payment/check/{transaction}', [PaymentController::class, 'checkStatus']);
// ─── Admin Wallet API ───
Route::post('/wallet/admin-adjust', [WalletController::class, 'adminAdjust']);
Route::post('/wallet/{wallet}/freeze', [WalletController::class, 'freeze']);
Route::post('/wallet/{wallet}/unfreeze', [WalletController::class, 'unfreeze']);
Route::get('/wallet/{wallet}/activity-log', [WalletController::class, 'activityLog']);
// ─── Discount Codes (نیازمند احراز هویت) ───
Route::get('/discount-codes', [DiscountCodeController::class, 'index']);
Route::post('/discount-codes/validate', [DiscountCodeController::class, 'validate']);
// ─── Commitment Forms (نیازمند احراز هویت) ───
Route::get('/commitment-forms', [CommitmentFormController::class, 'index']);
Route::get('/commitment-forms/{direction}', [CommitmentFormController::class, 'byDirection']);
// ─── Customer Orders API (جدید) ───
Route::prefix('customer')->group(function () {
// پروفایل و آمار
Route::get('/profile', [CustomerOrderController::class, 'profile']);
// لیست کشورها (عمومی - بدون نیاز به احراز هویت)
// این endpoint در گروه auth:sanctum نیست
// سفارشات
Route::get('/orders', [CustomerOrderController::class, 'index']);
Route::post('/orders', [CustomerOrderController::class, 'store']);
Route::get('/orders/{shipment}', [CustomerOrderController::class, 'show']);
Route::post('/orders/{shipment}/cancel', [CustomerOrderController::class, 'cancel']);
Route::post('/orders/{shipment}/resubmit', [CustomerOrderController::class, 'resubmit']);
// دانلود PDFهای سفارش
Route::get('/orders/{shipment}/pdf/awb', [ShipmentPdfController::class, 'awb']);
Route::get('/orders/{shipment}/pdf/invoice', [ShipmentPdfController::class, 'invoice']);
Route::get('/orders/{shipment}/pdf/label', [ShipmentPdfController::class, 'label']);
Route::get('/orders/{shipment}/pdf/import-invoice', [ShipmentPdfController::class, 'importInvoice']);
// تعهدنامه‌ها
Route::get('/orders/{shipment}/commitment-forms', [CommitmentFormController::class, 'shipmentForms']);
Route::post('/orders/{shipment}/commitment-forms/{form}/upload', [CommitmentFormController::class, 'uploadSigned']);
Route::get('/orders/{shipment}/commitment-forms/{form}/download', [CommitmentFormController::class, 'downloadSigned'])
->name('customer.commitment-forms.download');
// نوتیفیکیشن‌ها
Route::get('/notifications', [CustomerOrderController::class, 'notifications']);
Route::post('/notifications/{notification}/read', [CustomerOrderController::class, 'markNotificationRead']);
// پرداخت سفارش
Route::post('/orders/{shipment}/pay-wallet', [CustomerOrderController::class, 'payFromWallet']);
Route::post('/orders/{shipment}/pay-gateway', [CustomerOrderController::class, 'payViaGateway']);
});
// ─── Staff Orders API (تأیید سفارشات) ───
Route::middleware([StaffApiMiddleware::class])
->prefix('staff')
->group(function () {
Route::get(
'/orders/pending-approval',
[StaffOrderController::class, 'pendingApproval']
);
Route::post(
'/orders/{shipment}/request-changes',
[StaffOrderController::class, 'requestChanges']
);
Route::post(
'/orders/{shipment}/approve',
[StaffOrderController::class, 'approve']
);
Route::post(
'/orders/{shipment}/reject',
[StaffOrderController::class, 'reject']
);
// ─── Customer Financial API ───
Route::get(
'/customers/search',
[CustomerFinancialController::class, 'search']
);
Route::get(
'/customers/{customer}/financial-status',
[CustomerFinancialController::class, 'financialStatus']
);
});
});
// ══════════════════════════════════════════════════════════════
// Mock Gateway Routes (عمومی - برای شبیه‌سازی درگاه)
// ══════════════════════════════════════════════════════════════
Route::prefix('v1/payment')->group(function () {
Route::get('/mock-gateway', [MockGatewayController::class, 'showGateway']);
Route::get('/mock-gateway/success', [MockGatewayController::class, 'simulateSuccess']);
Route::get('/mock-gateway/failure', [MockGatewayController::class, 'simulateFailure']);
});
// Callback از درگاه (بدون auth)
Route::any('/v1/payment/callback', [PaymentController::class, 'callback'])
->name('payment.callback');
// ══════════════════════════════════════════════════════════════
// APIهای عمومی (بدون auth) — فقط استعلام قیمت همگانی است
// ══════════════════════════════════════════════════════════════
Route::post('/v1/calculate', [PricingController::class, 'calculate']);
// API تأیید موبایل (عمومی)
Route::post('/v1/verify/send-code', [MobileVerificationController::class, 'sendCode']);
Route::post('/v1/verify/check-code', [MobileVerificationController::class, 'checkCode']);
// API ارسال پیامک (نیاز به auth دارد)
Route::middleware(['auth:sanctum'])->post('/v1/verify/send-sms', [MobileVerificationController::class, 'sendSms']);