sms integration
This commit is contained in:
@@ -3,12 +3,15 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\ItemCollection;
|
||||
use App\Jobs\SendSmsJob;
|
||||
use App\Models\Area;
|
||||
use App\Models\BlockUser;
|
||||
use App\Models\Blog;
|
||||
use App\Models\Category;
|
||||
use App\Models\Chat;
|
||||
use App\Models\City;
|
||||
use App\Models\Client;
|
||||
use App\Models\Clientsreg;
|
||||
use App\Models\ContactUs;
|
||||
use App\Models\Country;
|
||||
use App\Models\Currency;
|
||||
@@ -3950,145 +3953,10 @@ class ApiController extends Controller
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
public function getOtp(Request $request)
|
||||
{
|
||||
try {
|
||||
$validator = Validator::make($request->query(), [
|
||||
'country_code' => 'required|string|max:5',
|
||||
'number' => 'required|string|max:15',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return ResponseService::validationError($validator->errors()->first());
|
||||
}
|
||||
|
||||
// Normalize inputs
|
||||
$countryCode = ltrim(trim($request->query('country_code')), '+');
|
||||
$number = preg_replace('/\D/', '', $request->query('number'));
|
||||
|
||||
$toNumber = '+' . $countryCode . $number;
|
||||
|
||||
$twilioSettings = Setting::whereIn('name', [
|
||||
'twilio_account_sid',
|
||||
'twilio_auth_token',
|
||||
'twilio_my_phone_number',
|
||||
])->pluck('value', 'name');
|
||||
|
||||
if ($twilioSettings->count() < 3) {
|
||||
return ResponseService::errorResponse(__('Twilio settings are missing.'));
|
||||
}
|
||||
|
||||
$client = new TwilioRestClient(
|
||||
$twilioSettings['twilio_account_sid'],
|
||||
$twilioSettings['twilio_auth_token']
|
||||
);
|
||||
|
||||
try {
|
||||
$client->lookups->v1->phoneNumbers($toNumber)->fetch();
|
||||
} catch (\Throwable $e) {
|
||||
return ResponseService::errorResponse(__('Invalid phone number.'));
|
||||
}
|
||||
|
||||
$otp = rand(100000, 999999);
|
||||
$expireAt = now()->addMinutes(10);
|
||||
|
||||
NumberOtp::updateOrCreate(
|
||||
[
|
||||
'number' => $number,
|
||||
],
|
||||
[
|
||||
'otp' => $otp,
|
||||
'expire_at' => $expireAt,
|
||||
]
|
||||
);
|
||||
|
||||
// Send OTP
|
||||
$client->messages->create($toNumber, [
|
||||
'from' => $twilioSettings['twilio_my_phone_number'],
|
||||
'body' => "Your OTP is: $otp. It expires in 10 minutes.",
|
||||
]);
|
||||
|
||||
return ResponseService::successResponse(__('OTP sent successfully.'));
|
||||
} catch (\Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'OTP Controller -> getOtp');
|
||||
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
|
||||
public function verifyOtp(Request $request)
|
||||
{
|
||||
try {
|
||||
$validator = Validator::make($request->all(), [
|
||||
'number' => 'required|string',
|
||||
'country_code' => 'required|string',
|
||||
'otp' => 'required|numeric|digits:6',
|
||||
'password' => 'nullable|string|min:6',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return ResponseService::validationError($validator->errors()->first());
|
||||
}
|
||||
|
||||
$number = $request->query('number');
|
||||
$countryCode = $request->query('country_code');
|
||||
|
||||
// Format full phone number
|
||||
// $requestNumber = $countryCode.$number;
|
||||
|
||||
// $trimmedNumber = ltrim($requestNumber, '+');
|
||||
// $toNumber = '+'.$trimmedNumber;
|
||||
|
||||
$otpRecord = NumberOtp::where('number', $number)->first();
|
||||
if (! $otpRecord) {
|
||||
return ResponseService::errorResponse(__('OTP not found.'));
|
||||
}
|
||||
if (now()->isAfter($otpRecord->expire_at)) {
|
||||
return ResponseService::validationError(__('OTP has expired.'));
|
||||
}
|
||||
|
||||
if ($otpRecord->attempts >= 3) {
|
||||
$otpRecord->delete();
|
||||
|
||||
return ResponseService::validationError(__('OTP expired after 3 failed attempts.'));
|
||||
}
|
||||
|
||||
if ($otpRecord->otp != $request->otp) {
|
||||
$otpRecord->increment('attempts');
|
||||
|
||||
return ResponseService::validationError(__('Invalid OTP.'));
|
||||
}
|
||||
$otpRecord->delete();
|
||||
|
||||
$user = User::where('mobile', $request->number)->where('type', 'phone')->first();
|
||||
|
||||
if (! $user) {
|
||||
$user = User::create([
|
||||
'mobile' => $request->number,
|
||||
'type' => 'phone',
|
||||
'country_code' => $countryCode,
|
||||
'password' => ! empty($request->password) ? Hash::make($request->password) : '',
|
||||
]);
|
||||
$user->assignRole('User');
|
||||
}else{
|
||||
if (! empty($countryCode)) {
|
||||
$user->country_code = ltrim($countryCode, '+');
|
||||
}
|
||||
$user->save();
|
||||
}
|
||||
|
||||
Auth::login($user);
|
||||
$auth = User::find(Auth::id());
|
||||
|
||||
$token = $auth->createToken($auth->name ?? '')->plainTextToken;
|
||||
|
||||
return ResponseService::successResponse(__('User logged-in successfully'), $auth, ['token' => $token]);
|
||||
} catch (Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'OTP Controller -> verifyOtp');
|
||||
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
public function userExists(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
|
||||
320
app/Http/Controllers/api/AuthController.php
Normal file
320
app/Http/Controllers/api/AuthController.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Controllers\api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\SendSmsJob;
|
||||
use App\Models\Clientsreg;
|
||||
use App\Services\ResponseService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/get-otp",
|
||||
* summary="Send OTP for registration",
|
||||
* tags={"Auth"},
|
||||
*
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(
|
||||
* required={"phone","device_type","password"},
|
||||
* @OA\Property(property="firstname", type="string", example="Devit"),
|
||||
* @OA\Property(property="lastname", type="string", example="Togo"),
|
||||
* @OA\Property(property="phone", type="string", example="901234567"),
|
||||
* @OA\Property(property="password", type="string", example="1234"),
|
||||
* @OA\Property(property="device_type", type="string", example="android"),
|
||||
* @OA\Property(property="fcm_token", type="string", example="token_here")
|
||||
* )
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="OTP sent successfully"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
|
||||
public function getOtp(Request $request)
|
||||
{
|
||||
try {
|
||||
$validator = Validator::make($request->all(), [
|
||||
'firstname' => 'nullable|string|max:100',
|
||||
'lastname' => 'nullable|string|max:100',
|
||||
'phone' => 'required|string|max:9',
|
||||
'fcm_token' => 'nullable|string',
|
||||
'device_type' => 'required|in:android,ios,web',
|
||||
'password' => 'required|string|min:4',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return ResponseService::validationError($validator->errors()->first());
|
||||
}
|
||||
|
||||
$phone = preg_replace('/\D/', '', $request->phone);
|
||||
|
||||
$client = Clientsreg::where('phone', $phone)->first();
|
||||
|
||||
if ($client) {
|
||||
|
||||
if ($client->active) {
|
||||
return ResponseService::errorResponse(__('You are already registered. Log in.'));
|
||||
}
|
||||
|
||||
if ($client->code_expires_at && now()->lt($client->code_expires_at)) {
|
||||
return ResponseService::errorResponse(__('The previous code is still valid. Please wait.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$otp = rand(1000, 9999);
|
||||
|
||||
$client = Clientsreg::updateOrCreate(
|
||||
['phone' => $phone],
|
||||
[
|
||||
'firstname' => $request->firstname,
|
||||
'lastname' => $request->lastname,
|
||||
'fcm_token' => $request->fcm_token,
|
||||
'device_type' => $request->device_type,
|
||||
'password' => bcrypt($request->password),
|
||||
'otp' => $otp, // ✅ MUHIM
|
||||
'code_sent_at' => now(),
|
||||
'code_expires_at' => now()->addMinutes(1),
|
||||
'active' => false,
|
||||
]
|
||||
);
|
||||
|
||||
dispatch(new SendSmsJob($phone, $otp));
|
||||
|
||||
return ResponseService::successResponse(__('OTP sent successfully.'));
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'OTP Controller -> getOtp');
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/verify-otp",
|
||||
* summary="Verify OTP code",
|
||||
* tags={"Auth"},
|
||||
*
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(
|
||||
* required={"phone","otp"},
|
||||
* @OA\Property(property="phone", type="string", example="998901234567"),
|
||||
* @OA\Property(property="otp", type="integer", example=1234)
|
||||
* )
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Phone verified successfully"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function verifyOtp(Request $request)
|
||||
{
|
||||
try {
|
||||
$validator = Validator::make($request->all(), [
|
||||
'phone' => 'required|string',
|
||||
'otp' => 'required|numeric|digits:4',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return ResponseService::validationError($validator->errors()->first());
|
||||
}
|
||||
|
||||
$phone = preg_replace('/\D/', '', $request->phone);
|
||||
|
||||
|
||||
$client = Clientsreg::where('phone', $phone)->first();
|
||||
|
||||
if (!$client) {
|
||||
return ResponseService::errorResponse(__('User not found.'));
|
||||
}
|
||||
|
||||
|
||||
if (!$client->code_expires_at || now()->gt($client->code_expires_at)) {
|
||||
return ResponseService::validationError(__('OTP has expired.'));
|
||||
}
|
||||
|
||||
|
||||
if ($client->otp != $request->otp) {
|
||||
return ResponseService::validationError(__('Invalid OTP.'));
|
||||
}
|
||||
|
||||
|
||||
$client->active = true;
|
||||
$client->otp = null;
|
||||
$client->code_expires_at = null;
|
||||
$client->save();
|
||||
|
||||
return ResponseService::successResponse(__('Phone verified successfully'), [
|
||||
'phone' => $phone,
|
||||
'verified' => true,
|
||||
]);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'OTP Controller -> verifyOtp');
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/login",
|
||||
* summary="User login",
|
||||
* tags={"Auth"},
|
||||
*
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
* @OA\JsonContent(
|
||||
* required={"phone","password","device_type"},
|
||||
* @OA\Property(property="phone", type="string", example="998901234567"),
|
||||
* @OA\Property(property="password", type="string", example="1234"),
|
||||
* @OA\Property(property="device_type", type="string", example="android"),
|
||||
* @OA\Property(property="fcm_token", type="string", example="token_here")
|
||||
* )
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Login successful",
|
||||
* @OA\JsonContent(
|
||||
* @OA\Property(property="token", type="string", example="1|abcdefg123456")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
try {
|
||||
$validator = Validator::make($request->all(), [
|
||||
'phone' => 'required|string|max:15',
|
||||
'password' => 'required|string|min:4',
|
||||
'device_type' => 'required|in:android,ios,web',
|
||||
'fcm_token' => 'nullable|string',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return ResponseService::validationError($validator->errors()->first());
|
||||
}
|
||||
|
||||
|
||||
$phone = preg_replace('/\D/', '', $request->phone);
|
||||
|
||||
|
||||
$client = Clientsreg::where('phone', $phone)->first();
|
||||
|
||||
if (!$client) {
|
||||
return ResponseService::errorResponse(__('User not found.'));
|
||||
}
|
||||
|
||||
if (!$client->active) {
|
||||
return ResponseService::errorResponse(__('Account not verified.'));
|
||||
}
|
||||
|
||||
|
||||
if (!Hash::check($request->password, $client->password)) {
|
||||
return ResponseService::errorResponse(__('Invalid password.'));
|
||||
}
|
||||
|
||||
|
||||
$client->update([
|
||||
'device_type' => $request->device_type,
|
||||
'fcm_token' => $request->fcm_token,
|
||||
]);
|
||||
|
||||
|
||||
$token = $client->createToken('client-token')->plainTextToken;
|
||||
|
||||
return ResponseService::successResponse(__('Login successful'), [
|
||||
'token' => $token,
|
||||
// 'user' => $client,
|
||||
]);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'Auth -> login');
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/profile",
|
||||
* summary="Get user profile",
|
||||
* tags={"Auth"},
|
||||
* security={{"bearerAuth":{}}},
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Profile data",
|
||||
* @OA\JsonContent(
|
||||
* @OA\Property(property="id", type="integer", example=1),
|
||||
* @OA\Property(property="firstname", type="string", example="Ali"),
|
||||
* @OA\Property(property="lastname", type="string", example="Valiyev"),
|
||||
* @OA\Property(property="phone", type="string", example="998901234567"),
|
||||
* @OA\Property(property="email", type="string", example="test@gmail.com"),
|
||||
* @OA\Property(property="device_type", type="string", example="android")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function profile(Request $request)
|
||||
{
|
||||
$client = $request->user();
|
||||
|
||||
return ResponseService::successResponse(__('Profile data'), [
|
||||
'id' => $client->id,
|
||||
'firstname' => $client->firstname,
|
||||
'lastname' => $client->lastname,
|
||||
'phone' => $client->phone,
|
||||
'email' => $client->email,
|
||||
'device_type' => $client->device_type,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/api/logout",
|
||||
* summary="Logout user",
|
||||
* tags={"Auth"},
|
||||
* security={{"bearerAuth":{}}},
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Logged out successfully"
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
try {
|
||||
$request->user()->currentAccessToken()->delete();
|
||||
|
||||
return ResponseService::successResponse(__('Logged out successfully'));
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
ResponseService::logErrorResponse($th, 'Auth -> logout');
|
||||
return ResponseService::errorResponse();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,8 +41,7 @@ class SendSmsJob implements ShouldQueue
|
||||
|
||||
$postData = [
|
||||
'mobile_phone' => $phoneNumber,
|
||||
'message' => "DELGO hisobiga kirish uchun kod: {$this->code} Ushbu kodni ulashmang! #WBcz5ARFKcp",
|
||||
// 'message' => "DELGO hisobiga kirish uchun kod: {$this->code} Ushbu kodni ulashmang! #WBcz5ARFKcp",
|
||||
'message' => "pedagog.uz sayti va mobil ilovasi uchun tasdiqlash kodi: {$this->code}",
|
||||
'from' => "4546"
|
||||
];
|
||||
|
||||
|
||||
38
app/Models/Clientsreg.php
Normal file
38
app/Models/Clientsreg.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
|
||||
class Clientsreg extends Model
|
||||
{
|
||||
use HasApiTokens, HasFactory;
|
||||
|
||||
|
||||
|
||||
protected $fillable = [
|
||||
'firstname',
|
||||
'lastname',
|
||||
'phone',
|
||||
'otp',
|
||||
'email',
|
||||
'fcm_token',
|
||||
'device_type',
|
||||
'active',
|
||||
'code_sent_at',
|
||||
'code_expires_at',
|
||||
'password',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'active' => 'boolean',
|
||||
'code_sent_at' => 'datetime',
|
||||
'code_expires_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
'password',
|
||||
];
|
||||
}
|
||||
@@ -27,6 +27,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
public function boot()
|
||||
{
|
||||
Schema::defaultStringLength(191);
|
||||
URL::forceScheme('https');
|
||||
URL::forceScheme('http');
|
||||
}
|
||||
}
|
||||
|
||||
36
app/Providers/HorizonServiceProvider.php
Normal file
36
app/Providers/HorizonServiceProvider.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Horizon\Horizon;
|
||||
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||
|
||||
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// Horizon::routeSmsNotificationsTo('15556667777');
|
||||
// Horizon::routeMailNotificationsTo('example@example.com');
|
||||
// Horizon::routeSlackNotificationsTo('slack-webhook-url', '#channel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Horizon gate.
|
||||
*
|
||||
* This gate determines who can access Horizon in non-local environments.
|
||||
*/
|
||||
protected function gate(): void
|
||||
{
|
||||
Gate::define('viewHorizon', function ($user = null) {
|
||||
return in_array(optional($user)->email, [
|
||||
//
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ class ResponseService
|
||||
public static function successResponse(?string $message = 'Success', $data = null, array $customData = [], $code = null): void
|
||||
{
|
||||
response()->json(array_merge([
|
||||
'error' => false,
|
||||
// 'error' => false,
|
||||
'message' => trans($message),
|
||||
'data' => $data,
|
||||
'code' => $code ?? config('constants.RESPONSE_CODE.SUCCESS'),
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"ext-zip": "*",
|
||||
"cerbero/json-parser": "^1.1",
|
||||
"dacoto/laravel-wizard-installer": "^1.0",
|
||||
"darkaonline/l5-swagger": "^8.6",
|
||||
"devaslanphp/auto-translate": "*",
|
||||
"doctrine/dbal": "^3.6",
|
||||
"flutterwavedev/flutterwave-v3": "^1.0",
|
||||
@@ -23,6 +24,7 @@
|
||||
"kingflamez/laravelrave": "4.2.1",
|
||||
"kornrunner/blurhash": "^1.2",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/horizon": "^5.45",
|
||||
"laravel/sanctum": "^3.2",
|
||||
"laravel/tinker": "^2.7",
|
||||
"laravel/ui": "^4.0",
|
||||
|
||||
363
composer.lock
generated
363
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1c68d79b2742d7cf0a2084553291436a",
|
||||
"content-hash": "f26653d3f245471f8c6e231a43a1f35e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
@@ -627,6 +627,86 @@
|
||||
},
|
||||
"time": "2024-02-12T21:48:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "darkaonline/l5-swagger",
|
||||
"version": "8.6.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/DarkaOnLine/L5-Swagger.git",
|
||||
"reference": "4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/DarkaOnLine/L5-Swagger/zipball/4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85",
|
||||
"reference": "4cf2b3faae9e9cffd05e4eb6e066741bf56f0a85",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/annotations": "^1.0 || ^2.0",
|
||||
"ext-json": "*",
|
||||
"laravel/framework": "^11.0 || ^10.0 || ^9.0 || >=8.40.0 || ^7.0",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"swagger-api/swagger-ui": "^3.0 || >=4.1.3",
|
||||
"symfony/yaml": "^5.0 || ^6.0 || ^7.0",
|
||||
"zircote/swagger-php": "^3.2.0 || ^4.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "1.*",
|
||||
"orchestra/testbench": "^9.0 || ^8.0 || 7.* || ^6.15 || 5.*",
|
||||
"php-coveralls/php-coveralls": "^2.0",
|
||||
"phpunit/phpunit": "^11.0 || ^10.0 || ^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"L5Swagger": "L5Swagger\\L5SwaggerFacade"
|
||||
},
|
||||
"providers": [
|
||||
"L5Swagger\\L5SwaggerServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"L5Swagger\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Darius Matulionis",
|
||||
"email": "darius@matulionis.lt"
|
||||
}
|
||||
],
|
||||
"description": "OpenApi or Swagger integration to Laravel",
|
||||
"keywords": [
|
||||
"api",
|
||||
"documentation",
|
||||
"laravel",
|
||||
"openapi",
|
||||
"specification",
|
||||
"swagger",
|
||||
"ui"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/DarkaOnLine/L5-Swagger/issues",
|
||||
"source": "https://github.com/DarkaOnLine/L5-Swagger/tree/8.6.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/DarkaOnLine",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-06T14:54:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "devaslanphp/auto-translate",
|
||||
"version": "1.0.0",
|
||||
@@ -745,6 +825,83 @@
|
||||
},
|
||||
"time": "2024-07-08T12:26:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
"version": "2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/annotations.git",
|
||||
"reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7",
|
||||
"reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "^2 || ^3",
|
||||
"ext-tokenizer": "*",
|
||||
"php": "^7.2 || ^8.0",
|
||||
"psr/cache": "^1 || ^2 || ^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "^2.0",
|
||||
"doctrine/coding-standard": "^10",
|
||||
"phpstan/phpstan": "^1.10.28",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"symfony/cache": "^5.4 || ^6.4 || ^7",
|
||||
"vimeo/psalm": "^4.30 || ^5.14"
|
||||
},
|
||||
"suggest": {
|
||||
"php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Docblock Annotations Parser",
|
||||
"homepage": "https://www.doctrine-project.org/projects/annotations.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"parser"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/annotations/issues",
|
||||
"source": "https://github.com/doctrine/annotations/tree/2.0.2"
|
||||
},
|
||||
"abandoned": true,
|
||||
"time": "2024-09-05T10:17:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "3.10.4",
|
||||
@@ -2722,6 +2879,86 @@
|
||||
},
|
||||
"time": "2025-11-28T18:20:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/horizon",
|
||||
"version": "v5.45.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/horizon.git",
|
||||
"reference": "b2b32e3f6013081e0176307e9081cd085f0ad4d6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/horizon/zipball/b2b32e3f6013081e0176307e9081cd085f0ad4d6",
|
||||
"reference": "b2b32e3f6013081e0176307e9081cd085f0ad4d6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-pcntl": "*",
|
||||
"ext-posix": "*",
|
||||
"illuminate/contracts": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/queue": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^9.21|^10.0|^11.0|^12.0|^13.0",
|
||||
"laravel/sentinel": "^1.0",
|
||||
"nesbot/carbon": "^2.17|^3.0",
|
||||
"php": "^8.0",
|
||||
"ramsey/uuid": "^4.0",
|
||||
"symfony/console": "^6.0|^7.0|^8.0",
|
||||
"symfony/error-handler": "^6.0|^7.0|^8.0",
|
||||
"symfony/polyfill-php83": "^1.28",
|
||||
"symfony/process": "^6.0|^7.0|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1.0",
|
||||
"orchestra/testbench": "^7.56|^8.37|^9.16|^10.9|^11.0",
|
||||
"phpstan/phpstan": "^1.10|^2.0",
|
||||
"predis/predis": "^1.1|^2.0|^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-redis": "Required to use the Redis PHP driver.",
|
||||
"predis/predis": "Required when not using the Redis PHP driver (^1.1|^2.0|^3.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Horizon": "Laravel\\Horizon\\Horizon"
|
||||
},
|
||||
"providers": [
|
||||
"Laravel\\Horizon\\HorizonServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Horizon\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Dashboard and code-driven configuration for Laravel queues.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"queue"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/horizon/issues",
|
||||
"source": "https://github.com/laravel/horizon/tree/v5.45.4"
|
||||
},
|
||||
"time": "2026-03-18T14:14:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.1.25",
|
||||
@@ -2846,6 +3083,65 @@
|
||||
},
|
||||
"time": "2023-12-19T18:44:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/sentinel",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/sentinel.git",
|
||||
"reference": "7a98db53e0d9d6f61387f3141c07477f97425603"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/sentinel/zipball/7a98db53e0d9d6f61387f3141c07477f97425603",
|
||||
"reference": "7a98db53e0d9d6f61387f3141c07477f97425603",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"illuminate/container": "^8.37|^9.0|^10.0|^11.0|^12.0|^13.0",
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.27",
|
||||
"orchestra/testbench": "^6.47.1|^7.56|^8.37|^9.16|^10.9|^11.0",
|
||||
"phpstan/phpstan": "^2.1.33"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Sentinel\\SentinelServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Sentinel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
},
|
||||
{
|
||||
"name": "Mior Muhammad Zaki",
|
||||
"email": "mior@laravel.com"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/laravel/sentinel/tree/v1.0.1"
|
||||
},
|
||||
"time": "2026-02-12T13:32:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
"version": "v1.3.7",
|
||||
@@ -7103,6 +7399,67 @@
|
||||
},
|
||||
"time": "2016-11-22T22:57:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swagger-api/swagger-ui",
|
||||
"version": "v5.32.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/swagger-api/swagger-ui.git",
|
||||
"reference": "d361f5b3570b8ade67fb1c02cf7a676fcb441479"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/d361f5b3570b8ade67fb1c02cf7a676fcb441479",
|
||||
"reference": "d361f5b3570b8ade67fb1c02cf7a676fcb441479",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anna Bodnia",
|
||||
"email": "anna.bodnia@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Buu Nguyen",
|
||||
"email": "buunguyen@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Josh Ponelat",
|
||||
"email": "jponelat@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Kyle Shockey",
|
||||
"email": "kyleshockey1@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Robert Barnwell",
|
||||
"email": "robert@robertismy.name"
|
||||
},
|
||||
{
|
||||
"name": "Sahar Jafari",
|
||||
"email": "shr.jafari@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.",
|
||||
"homepage": "http://swagger.io",
|
||||
"keywords": [
|
||||
"api",
|
||||
"documentation",
|
||||
"openapi",
|
||||
"specification",
|
||||
"swagger",
|
||||
"ui"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/swagger-api/swagger-ui/issues",
|
||||
"source": "https://github.com/swagger-api/swagger-ui/tree/v5.32.1"
|
||||
},
|
||||
"time": "2026-03-17T14:00:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/browser-kit",
|
||||
"version": "v6.4.31",
|
||||
@@ -14157,6 +14514,6 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-zip": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.6.0"
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
}
|
||||
|
||||
254
config/horizon.php
Normal file
254
config/horizon.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This name appears in notifications and in the Horizon UI. Unique names
|
||||
| can be useful while running multiple instances of Horizon within an
|
||||
| application, allowing you to identify the Horizon you're viewing.
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('HORIZON_NAME'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Horizon will be accessible from. If this
|
||||
| setting is null, Horizon will reside under the same domain as the
|
||||
| application. Otherwise, this value will serve as the subdomain.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('HORIZON_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Horizon will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('HORIZON_PATH', 'horizon'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the name of the Redis connection where Horizon will store the
|
||||
| meta information required for it to function. It includes the list
|
||||
| of supervisors, failed jobs, job metrics, and other information.
|
||||
|
|
||||
*/
|
||||
|
||||
'use' => 'default',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This prefix will be used when storing all Horizon data in Redis. You
|
||||
| may modify the prefix when you are running multiple installations
|
||||
| of Horizon on the same server so that they don't have problems.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env(
|
||||
'HORIZON_PREFIX',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_horizon:'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will get attached onto each Horizon route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => ['web'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Wait Time Thresholds
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to configure when the LongWaitDetected event
|
||||
| will be fired. Every connection / queue combination may have its
|
||||
| own, unique threshold (in seconds) before this event is fired.
|
||||
|
|
||||
*/
|
||||
|
||||
'waits' => [
|
||||
'redis:default' => 60,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Trimming Times
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure for how long (in minutes) you desire Horizon to
|
||||
| persist the recent and failed jobs. Typically, recent jobs are kept
|
||||
| for one hour while all failed jobs are stored for an entire week.
|
||||
|
|
||||
*/
|
||||
|
||||
'trim' => [
|
||||
'recent' => 60,
|
||||
'pending' => 60,
|
||||
'completed' => 60,
|
||||
'recent_failed' => 10080,
|
||||
'failed' => 10080,
|
||||
'monitored' => 10080,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Silenced Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Silencing a job will instruct Horizon to not place the job in the list
|
||||
| of completed jobs within the Horizon dashboard. This setting may be
|
||||
| used to fully remove any noisy jobs from the completed jobs list.
|
||||
|
|
||||
*/
|
||||
|
||||
'silenced' => [
|
||||
// App\Jobs\ExampleJob::class,
|
||||
],
|
||||
|
||||
'silenced_tags' => [
|
||||
// 'notifications',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Metrics
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure how many snapshots should be kept to display in
|
||||
| the metrics graph. This will get used in combination with Horizon's
|
||||
| `horizon:snapshot` schedule to define how long to retain metrics.
|
||||
|
|
||||
*/
|
||||
|
||||
'metrics' => [
|
||||
'trim_snapshots' => [
|
||||
'job' => 24,
|
||||
'queue' => 24,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fast Termination
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this option is enabled, Horizon's "terminate" command will not
|
||||
| wait on all of the workers to terminate unless the --wait option
|
||||
| is provided. Fast termination can shorten deployment delay by
|
||||
| allowing a new instance of Horizon to start while the last
|
||||
| instance will continue to terminate each of its workers.
|
||||
|
|
||||
*/
|
||||
|
||||
'fast_termination' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Memory Limit (MB)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value describes the maximum amount of memory the Horizon master
|
||||
| supervisor may consume before it is terminated and restarted. For
|
||||
| configuring these limits on your workers, see the next section.
|
||||
|
|
||||
*/
|
||||
|
||||
'memory_limit' => 64,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Worker Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the queue worker settings used by your application
|
||||
| in all environments. These supervisors and settings handle all your
|
||||
| queued jobs and will be provisioned by Horizon during deployment.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'supervisor-1' => [
|
||||
'connection' => 'redis',
|
||||
'queue' => ['default'],
|
||||
'balance' => 'auto',
|
||||
'autoScalingStrategy' => 'time',
|
||||
'maxProcesses' => 1,
|
||||
'maxTime' => 0,
|
||||
'maxJobs' => 0,
|
||||
'memory' => 128,
|
||||
'tries' => 1,
|
||||
'timeout' => 60,
|
||||
'nice' => 0,
|
||||
],
|
||||
],
|
||||
|
||||
'environments' => [
|
||||
'production' => [
|
||||
'supervisor-1' => [
|
||||
'maxProcesses' => 10,
|
||||
'balanceMaxShift' => 1,
|
||||
'balanceCooldown' => 3,
|
||||
],
|
||||
],
|
||||
|
||||
'local' => [
|
||||
'supervisor-1' => [
|
||||
'maxProcesses' => 3,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File Watcher Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following list of directories and files will be watched when using
|
||||
| the `horizon:listen` command. Whenever any directories or files are
|
||||
| changed, Horizon will automatically restart to apply all changes.
|
||||
|
|
||||
*/
|
||||
|
||||
'watch' => [
|
||||
'app',
|
||||
'bootstrap',
|
||||
'config/**/*.php',
|
||||
'database/**/*.php',
|
||||
'public/**/*.php',
|
||||
'resources/**/*.php',
|
||||
'routes',
|
||||
'composer.lock',
|
||||
'composer.json',
|
||||
'.env',
|
||||
],
|
||||
];
|
||||
318
config/l5-swagger.php
Normal file
318
config/l5-swagger.php
Normal file
@@ -0,0 +1,318 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'default' => 'default',
|
||||
'documentations' => [
|
||||
'default' => [
|
||||
'api' => [
|
||||
'title' => 'L5 Swagger UI',
|
||||
],
|
||||
|
||||
'routes' => [
|
||||
/*
|
||||
* Route for accessing api documentation interface
|
||||
*/
|
||||
'api' => 'api/documentation',
|
||||
],
|
||||
'paths' => [
|
||||
/*
|
||||
* Edit to include full URL in ui for assets
|
||||
*/
|
||||
'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true),
|
||||
|
||||
/*
|
||||
* Edit to set path where swagger ui assets should be stored
|
||||
*/
|
||||
'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'),
|
||||
|
||||
/*
|
||||
* File name of the generated json documentation file
|
||||
*/
|
||||
'docs_json' => 'api-docs.json',
|
||||
|
||||
/*
|
||||
* File name of the generated YAML documentation file
|
||||
*/
|
||||
'docs_yaml' => 'api-docs.yaml',
|
||||
|
||||
/*
|
||||
* Set this to `json` or `yaml` to determine which documentation file to use in UI
|
||||
*/
|
||||
'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'),
|
||||
|
||||
/*
|
||||
* Absolute paths to directory containing the swagger annotations are stored.
|
||||
*/
|
||||
'annotations' => [
|
||||
base_path('app'),
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'defaults' => [
|
||||
'routes' => [
|
||||
/*
|
||||
* Route for accessing parsed swagger annotations.
|
||||
*/
|
||||
'docs' => 'docs',
|
||||
|
||||
/*
|
||||
* Route for Oauth2 authentication callback.
|
||||
*/
|
||||
'oauth2_callback' => 'api/oauth2-callback',
|
||||
|
||||
/*
|
||||
* Middleware allows to prevent unexpected access to API documentation
|
||||
*/
|
||||
'middleware' => [
|
||||
'api' => [],
|
||||
'asset' => [],
|
||||
'docs' => [],
|
||||
'oauth2_callback' => [],
|
||||
],
|
||||
|
||||
/*
|
||||
* Route Group options
|
||||
*/
|
||||
'group_options' => [],
|
||||
],
|
||||
|
||||
'paths' => [
|
||||
/*
|
||||
* Absolute path to location where parsed annotations will be stored
|
||||
*/
|
||||
'docs' => storage_path('api-docs'),
|
||||
|
||||
/*
|
||||
* Absolute path to directory where to export views
|
||||
*/
|
||||
'views' => base_path('resources/views/vendor/l5-swagger'),
|
||||
|
||||
/*
|
||||
* Edit to set the api's base path
|
||||
*/
|
||||
'base' => env('L5_SWAGGER_BASE_PATH', null),
|
||||
|
||||
/*
|
||||
* Absolute path to directories that should be excluded from scanning
|
||||
* @deprecated Please use `scanOptions.exclude`
|
||||
* `scanOptions.exclude` overwrites this
|
||||
*/
|
||||
'excludes' => [],
|
||||
],
|
||||
|
||||
'scanOptions' => [
|
||||
/**
|
||||
* Configuration for default processors. Allows to pass processors configuration to swagger-php.
|
||||
*
|
||||
* @link https://zircote.github.io/swagger-php/reference/processors.html
|
||||
*/
|
||||
'default_processors_configuration' => [
|
||||
/** Example */
|
||||
/**
|
||||
* 'operationId.hash' => true,
|
||||
* 'pathFilter' => [
|
||||
* 'tags' => [
|
||||
* '/pets/',
|
||||
* '/store/',
|
||||
* ],
|
||||
* ],.
|
||||
*/
|
||||
],
|
||||
|
||||
/**
|
||||
* analyser: defaults to \OpenApi\StaticAnalyser .
|
||||
*
|
||||
* @see \OpenApi\scan
|
||||
*/
|
||||
'analyser' => null,
|
||||
|
||||
/**
|
||||
* analysis: defaults to a new \OpenApi\Analysis .
|
||||
*
|
||||
* @see \OpenApi\scan
|
||||
*/
|
||||
'analysis' => null,
|
||||
|
||||
/**
|
||||
* Custom query path processors classes.
|
||||
*
|
||||
* @link https://github.com/zircote/swagger-php/tree/master/Examples/processors/schema-query-parameter
|
||||
* @see \OpenApi\scan
|
||||
*/
|
||||
'processors' => [
|
||||
// new \App\SwaggerProcessors\SchemaQueryParameter(),
|
||||
],
|
||||
|
||||
/**
|
||||
* pattern: string $pattern File pattern(s) to scan (default: *.php) .
|
||||
*
|
||||
* @see \OpenApi\scan
|
||||
*/
|
||||
'pattern' => null,
|
||||
|
||||
/*
|
||||
* Absolute path to directories that should be excluded from scanning
|
||||
* @note This option overwrites `paths.excludes`
|
||||
* @see \OpenApi\scan
|
||||
*/
|
||||
'exclude' => [],
|
||||
|
||||
/*
|
||||
* Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0.
|
||||
* By default the spec will be in version 3.0.0
|
||||
*/
|
||||
'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION),
|
||||
],
|
||||
|
||||
/*
|
||||
* API security definitions. Will be generated into documentation file.
|
||||
*/
|
||||
'securityDefinitions' => [
|
||||
'securitySchemes' => [
|
||||
/*
|
||||
* Examples of Security schemes
|
||||
*/
|
||||
/*
|
||||
'api_key_security_example' => [ // Unique name of security
|
||||
'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
|
||||
'description' => 'A short description for security scheme',
|
||||
'name' => 'api_key', // The name of the header or query parameter to be used.
|
||||
'in' => 'header', // The location of the API key. Valid values are "query" or "header".
|
||||
],
|
||||
'oauth2_security_example' => [ // Unique name of security
|
||||
'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
|
||||
'description' => 'A short description for oauth2 security scheme.',
|
||||
'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode".
|
||||
'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode)
|
||||
//'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode)
|
||||
'scopes' => [
|
||||
'read:projects' => 'read your projects',
|
||||
'write:projects' => 'modify projects in your account',
|
||||
]
|
||||
],
|
||||
*/
|
||||
|
||||
/* Open API 3.0 support
|
||||
'passport' => [ // Unique name of security
|
||||
'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
|
||||
'description' => 'Laravel passport oauth2 security.',
|
||||
'in' => 'header',
|
||||
'scheme' => 'https',
|
||||
'flows' => [
|
||||
"password" => [
|
||||
"authorizationUrl" => config('app.url') . '/oauth/authorize',
|
||||
"tokenUrl" => config('app.url') . '/oauth/token',
|
||||
"refreshUrl" => config('app.url') . '/token/refresh',
|
||||
"scopes" => []
|
||||
],
|
||||
],
|
||||
],
|
||||
'sanctum' => [ // Unique name of security
|
||||
'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2".
|
||||
'description' => 'Enter token in format (Bearer <token>)',
|
||||
'name' => 'Authorization', // The name of the header or query parameter to be used.
|
||||
'in' => 'header', // The location of the API key. Valid values are "query" or "header".
|
||||
],
|
||||
*/
|
||||
],
|
||||
'security' => [
|
||||
/*
|
||||
* Examples of Securities
|
||||
*/
|
||||
[
|
||||
/*
|
||||
'oauth2_security_example' => [
|
||||
'read',
|
||||
'write'
|
||||
],
|
||||
|
||||
'passport' => []
|
||||
*/
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
* Set this to `true` in development mode so that docs would be regenerated on each request
|
||||
* Set this to `false` to disable swagger generation on production
|
||||
*/
|
||||
'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false),
|
||||
|
||||
/*
|
||||
* Set this to `true` to generate a copy of documentation in yaml format
|
||||
*/
|
||||
'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false),
|
||||
|
||||
/*
|
||||
* Edit to trust the proxy's ip address - needed for AWS Load Balancer
|
||||
* string[]
|
||||
*/
|
||||
'proxy' => false,
|
||||
|
||||
/*
|
||||
* Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle.
|
||||
* See more at: https://github.com/swagger-api/swagger-ui#configs-plugin
|
||||
*/
|
||||
'additional_config_url' => null,
|
||||
|
||||
/*
|
||||
* Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically),
|
||||
* 'method' (sort by HTTP method).
|
||||
* Default is the order returned by the server unchanged.
|
||||
*/
|
||||
'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null),
|
||||
|
||||
/*
|
||||
* Pass the validatorUrl parameter to SwaggerUi init on the JS side.
|
||||
* A null value here disables validation.
|
||||
*/
|
||||
'validator_url' => null,
|
||||
|
||||
/*
|
||||
* Swagger UI configuration parameters
|
||||
*/
|
||||
'ui' => [
|
||||
'display' => [
|
||||
'dark_mode' => env('L5_SWAGGER_UI_DARK_MODE', false),
|
||||
/*
|
||||
* Controls the default expansion setting for the operations and tags. It can be :
|
||||
* 'list' (expands only the tags),
|
||||
* 'full' (expands the tags and operations),
|
||||
* 'none' (expands nothing).
|
||||
*/
|
||||
'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'),
|
||||
|
||||
/**
|
||||
* If set, enables filtering. The top bar will show an edit box that
|
||||
* you can use to filter the tagged operations that are shown. Can be
|
||||
* Boolean to enable or disable, or a string, in which case filtering
|
||||
* will be enabled using that string as the filter expression. Filtering
|
||||
* is case-sensitive matching the filter expression anywhere inside
|
||||
* the tag.
|
||||
*/
|
||||
'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false
|
||||
],
|
||||
|
||||
'authorization' => [
|
||||
/*
|
||||
* If set to true, it persists authorization data, and it would not be lost on browser close/refresh
|
||||
*/
|
||||
'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false),
|
||||
|
||||
'oauth2' => [
|
||||
/*
|
||||
* If set to true, adds PKCE to AuthorizationCodeGrant flow
|
||||
*/
|
||||
'use_pkce_with_authorization_code_grant' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
/*
|
||||
* Constants which can be used in annotations
|
||||
*/
|
||||
'constants' => [
|
||||
'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'),
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -31,4 +31,10 @@ return [
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
|
||||
'eskiz' => [
|
||||
'email' => env('ESKIZ_EMAIL', ''),
|
||||
'password' => env('ESKIZ_PASSWORD', ''),
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('clientsregs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('firstname',100)->nullable();
|
||||
$table->string('lastname',100)->nullable();
|
||||
$table->string('phone',15)->unique();
|
||||
$table->string('otp',15)->nullable();
|
||||
$table->string('email', 150)->unique()->nullable()->comment('Foydalanuvchi email manzili');
|
||||
$table->text('fcm_token')->nullable()->comment('Firebase token manzili');
|
||||
$table->enum('device_type', ['android', 'ios', 'web'])->nullable()->comment('Qurilma turi');
|
||||
$table->boolean('active')->default(false);
|
||||
$table->timestamp('code_sent_at')->nullable();
|
||||
$table->timestamp('code_expires_at')->nullable();
|
||||
$table->string('password',)->nullable()->comment('Parol');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('clientsregs');
|
||||
}
|
||||
};
|
||||
0
resources/views/vendor/l5-swagger/.gitkeep
vendored
Normal file
0
resources/views/vendor/l5-swagger/.gitkeep
vendored
Normal file
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\api\AuthController;
|
||||
use App\Http\Controllers\ApiController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -72,11 +73,23 @@ Route::group(['middleware' => ['auth:sanctum']], static function () {
|
||||
});
|
||||
|
||||
|
||||
|
||||
Route::post('get-otp', [AuthController::class, 'getOtp']);
|
||||
Route::post('verify-otp', [AuthController::class, 'verifyOtp']);
|
||||
Route::post('login', [AuthController::class, 'login']);
|
||||
|
||||
|
||||
|
||||
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::get('profile', [AuthController::class, 'profile']);
|
||||
Route::get('logout', [AuthController::class, 'logout']);
|
||||
});
|
||||
|
||||
|
||||
/* Non Authenticated Routes */
|
||||
Route::get('user-exists', [ApiController::class, 'userExists']);
|
||||
Route::get('get-currencies', [ApiController::class, 'getCurrencies']);
|
||||
Route::get('get-otp', [ApiController::class, 'getOtp']);
|
||||
Route::get('verify-otp', [ApiController::class, 'verifyOtp']);
|
||||
Route::get('get-package', [ApiController::class, 'getPackage']);
|
||||
Route::get('get-languages', [ApiController::class, 'getLanguages']);
|
||||
Route::post('user-signup', [ApiController::class, 'userSignup']);
|
||||
|
||||
249
storage/api-docs/api-docs.json
Normal file
249
storage/api-docs/api-docs.json
Normal file
@@ -0,0 +1,249 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "Eclassify API",
|
||||
"description": "Eclassify api documentation",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/get-otp": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Send OTP for registration",
|
||||
"operationId": "9665576026de3c8975fefbf59380584a",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"required": [
|
||||
"phone",
|
||||
"device_type",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"firstname": {
|
||||
"type": "string",
|
||||
"example": "Devit"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string",
|
||||
"example": "Togo"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "901234567"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "1234"
|
||||
},
|
||||
"device_type": {
|
||||
"type": "string",
|
||||
"example": "android"
|
||||
},
|
||||
"fcm_token": {
|
||||
"type": "string",
|
||||
"example": "token_here"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OTP sent successfully"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/verify-otp": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Verify OTP code",
|
||||
"operationId": "1f09b8b2173f8afbe842b19937649fbb",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"required": [
|
||||
"phone",
|
||||
"otp"
|
||||
],
|
||||
"properties": {
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "998901234567"
|
||||
},
|
||||
"otp": {
|
||||
"type": "integer",
|
||||
"example": 1234
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Phone verified successfully"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/login": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "User login",
|
||||
"operationId": "dcf90ce65219b0ad51fc32e9f7f69843",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"required": [
|
||||
"phone",
|
||||
"password",
|
||||
"device_type"
|
||||
],
|
||||
"properties": {
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "998901234567"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"example": "1234"
|
||||
},
|
||||
"device_type": {
|
||||
"type": "string",
|
||||
"example": "android"
|
||||
},
|
||||
"fcm_token": {
|
||||
"type": "string",
|
||||
"example": "token_here"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Login successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string",
|
||||
"example": "1|abcdefg123456"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/profile": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Get user profile",
|
||||
"operationId": "4ed7ca3229d16b0b14785695794359e6",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Profile data",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"firstname": {
|
||||
"type": "string",
|
||||
"example": "Ali"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string",
|
||||
"example": "Valiyev"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"example": "998901234567"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"example": "test@gmail.com"
|
||||
},
|
||||
"device_type": {
|
||||
"type": "string",
|
||||
"example": "android"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/logout": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Logout user",
|
||||
"operationId": "edf2b3b2f5fefa33e2fd224d2f2505c4",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Logged out successfully"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"bearerAuth": {
|
||||
"type": "http",
|
||||
"bearerFormat": "JWT",
|
||||
"scheme": "bearer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "Auth",
|
||||
"description": "Auth"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user