Compare commits
10
Commits
bf0cb80bd0
...
ae6b32a0b2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae6b32a0b2 | ||
|
|
bc86c41578 | ||
|
|
e6b0ad6cf9 | ||
|
|
acf2ed7f18 | ||
|
|
06cdf30f0a | ||
|
|
e98c0502db | ||
|
|
bbe70011dc | ||
|
|
854bd4101f | ||
|
|
ffda368718 | ||
|
|
0edece042f |
@@ -156,13 +156,13 @@ public function subscribe(Request $request, $packageName, $productId)
|
||||
}
|
||||
|
||||
if ($data['gateway'] == 'myket') {
|
||||
$service = new MyketService($product->packageName->cafeConfig);
|
||||
$purchaseStatus = $service->checkPurchase($product, $data['purchase_token']);
|
||||
if (!$purchaseStatus['status']) {
|
||||
return response()->json([
|
||||
'message' => $purchaseStatus['message'],
|
||||
], 400);
|
||||
}
|
||||
// $service = new MyketService($product->packageName->cafeConfig);
|
||||
// $purchaseStatus = $service->checkPurchase($product, $data['purchase_token']);
|
||||
// if (!$purchaseStatus['status']) {
|
||||
// return response()->json([
|
||||
// 'message' => $purchaseStatus['message'],
|
||||
// ], 400);
|
||||
// }
|
||||
$user->transactions()->create([
|
||||
'amount' => $product->price,
|
||||
'authority' => $data['purchase_token'],
|
||||
|
||||
@@ -6,19 +6,33 @@
|
||||
use App\Models\Reminder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Enums\ReminderType;
|
||||
use App\ReminderType;
|
||||
use Illuminate\Validation\Rules\Enum;
|
||||
|
||||
class ReminderController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$reminders = Reminder::where('user_id', Auth::id())
|
||||
->orderBy('time')
|
||||
->get();
|
||||
public function index(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'type' => ['nullable', new Enum(ReminderType::class)],
|
||||
'package_name' => ['nullable', 'exists:package_names,name'],
|
||||
]);
|
||||
|
||||
return response()->json($reminders);
|
||||
}
|
||||
$reminders = Reminder::query()
|
||||
->where('user_id', Auth::id())
|
||||
->when($request->type, function ($q) use ($request) {
|
||||
$q->where('type', $request->type);
|
||||
})
|
||||
->when($request->package_name, function ($q) use ($request) {
|
||||
$q->whereHas('packageName', function ($q2) use ($request) {
|
||||
$q2->where('name', $request->package_name);
|
||||
});
|
||||
})
|
||||
->orderBy('time')
|
||||
->get();
|
||||
|
||||
return response()->json($reminders);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Helpers\MobileNumberHelper;
|
||||
use App\Jobs\SendSMSJob;
|
||||
use App\Jobs\SendOTPJob;
|
||||
use App\Models\PackageName;
|
||||
use App\Models\Product;
|
||||
use App\Models\Transaction;
|
||||
@@ -230,21 +231,21 @@ public function register(Request $request)
|
||||
$code = rand(1000, 9999);
|
||||
$token = Str::random(64);
|
||||
// ✅ Check if email can receive a message before creating the user
|
||||
if (isset($data['email'])) {
|
||||
// $code = rand(1000, 9999);
|
||||
try {
|
||||
if ($method === 'code') {
|
||||
\Mail::to($data['email'])->send(new \App\Mail\VerifyEmailCodeMail($code));
|
||||
} else {
|
||||
$verificationUrl = url("api/auth/verify-email-link/{$token}?package={$packageNameValue}");
|
||||
\Mail::to($data['email'])->send(new \App\Mail\VerifyEmailLinkMail($verificationUrl));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'error' => $e->getMessage(),
|
||||
'message' => 'لطفا آدرس ایمیل خود را بررسی کنید و مجدد تلاش کنید'
|
||||
], 400);
|
||||
}
|
||||
// if (isset($data['email'])) {
|
||||
// $code = rand(1000, 9999);
|
||||
// try {
|
||||
// if ($method === 'code') {
|
||||
// \Mail::to($data['email'])->send(new \App\Mail\VerifyEmailCodeMail($code));
|
||||
// } else {
|
||||
// $verificationUrl = url("api/auth/verify-email-link/{$token}?package={$packageNameValue}");
|
||||
// \Mail::to($data['email'])->send(new \App\Mail\VerifyEmailLinkMail($verificationUrl));
|
||||
// }
|
||||
// } catch (\Exception $e) {
|
||||
// return response()->json([
|
||||
// 'error' => $e->getMessage(),
|
||||
// 'message' => 'لطفا آدرس ایمیل خود را بررسی کنید و مجدد تلاش کنید'
|
||||
// ], 400);
|
||||
// }
|
||||
// try {
|
||||
// // Try sending email
|
||||
// \Mail::to($data['email'])->send(new \App\Mail\VerifyEmailCodeMail($code));
|
||||
@@ -256,7 +257,7 @@ public function register(Request $request)
|
||||
|
||||
// ], 400);
|
||||
// }
|
||||
}
|
||||
// }
|
||||
|
||||
// Hash password
|
||||
$data['password'] = isset($data['password'])
|
||||
@@ -392,12 +393,13 @@ public function loginOTP(Request $request)
|
||||
]);
|
||||
|
||||
$verify = Str::random(8);
|
||||
SendSMSJob::dispatch([
|
||||
'mobile' => $data['mobile'],
|
||||
'message' => "کد ورود به برنامه: $otpToken
|
||||
@{$packageName->web_app_url} #$otpToken
|
||||
لغو 11"
|
||||
]);
|
||||
SendOTPJob::dispatch($data['mobile'], (string)$otpToken);
|
||||
// SendSMSJob::dispatch([
|
||||
// 'mobile' => $data['mobile'],
|
||||
// 'message' => "کد ورود به برنامه: $otpToken
|
||||
// @{$packageName->web_app_url} #$otpToken
|
||||
// لغو 11"
|
||||
// ]);
|
||||
}
|
||||
|
||||
if (!$user->packageNames()->where('package_names.id', $packageName->id)->exists()) {
|
||||
@@ -451,7 +453,71 @@ public function checkOTP(Request $request)
|
||||
'token' => $token,
|
||||
]);
|
||||
}
|
||||
public function requestMobileVerification(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'mobile' => ['required', 'string', new MobileNumber],
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
$mobile = MobileNumberHelper::formatMobile($data['mobile']);
|
||||
|
||||
// چک اینکه موبایل مال یوزر دیگه نباشه
|
||||
if (User::where('mobile', $mobile)
|
||||
->where('id', '!=', $user->id)
|
||||
->exists()) {
|
||||
return response()->json([
|
||||
'message' => 'mobile already taken'
|
||||
], 400);
|
||||
}
|
||||
|
||||
// حذف otp های قبلی
|
||||
$user->otpTokens()->delete();
|
||||
|
||||
$otp = rand(10000, 99999);
|
||||
|
||||
$user->otpTokens()->create([
|
||||
'token' => $otp
|
||||
]);
|
||||
|
||||
SendOTPJob::dispatch($mobile, (string)$otp);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'otp sent successfully'
|
||||
]);
|
||||
}
|
||||
public function confirmMobileVerification(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
'mobile' => ['required', 'string', new MobileNumber],
|
||||
'token' => 'required|string'
|
||||
]);
|
||||
|
||||
$user = auth()->user();
|
||||
$mobile = MobileNumberHelper::formatMobile($data['mobile']);
|
||||
|
||||
$otp = $user->otpTokens()
|
||||
->where('token', $data['token'])
|
||||
->where('created_at', '>', now()->subMinutes(5))
|
||||
->first();
|
||||
|
||||
if (!$otp) {
|
||||
return response()->json([
|
||||
'message' => 'invalid or expired token'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$otp->delete();
|
||||
|
||||
$user->update([
|
||||
'mobile' => $mobile,
|
||||
'mobile_verified_at' => now(),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'mobile verified successfully'
|
||||
]);
|
||||
}
|
||||
public function updateProfile(Request $request)
|
||||
{
|
||||
$data = $request->validate([
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Services\KavenegarService;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SendOTPJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct(
|
||||
private string $mobile,
|
||||
private string $token
|
||||
) {}
|
||||
|
||||
public function handle(KavenegarService $service)
|
||||
{
|
||||
$response = $service->sendVerify($this->mobile, $this->token);
|
||||
|
||||
logger()->info('Kavenegar response', $response);
|
||||
|
||||
if (!isset($response['return']) || $response['return']['status'] != 200) {
|
||||
logger()->error('Kavenegar failed', $response);
|
||||
throw new \Exception(json_encode($response));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
use App\ReminderType;
|
||||
class Reminder extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
+7
-1
@@ -20,6 +20,9 @@ class User extends Authenticatable
|
||||
'female' => 2,
|
||||
];
|
||||
protected $guarded = [];
|
||||
protected $casts = [
|
||||
'mobile_verified_at' => 'datetime',
|
||||
];
|
||||
protected $hidden = [
|
||||
'password',
|
||||
];
|
||||
@@ -39,7 +42,10 @@ public function getFullNameAttribute()
|
||||
{
|
||||
return $this->first_name . ' ' . $this->last_name;
|
||||
}
|
||||
|
||||
public function hasVerifiedMobile(): bool
|
||||
{
|
||||
return !is_null($this->mobile_verified_at);
|
||||
}
|
||||
public function getAvatarAttribute()
|
||||
{
|
||||
return isset($this->attributes['avatar']) ? url($this->attributes['avatar']) : null;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class KavenegarService
|
||||
{
|
||||
public function sendVerify(string $mobile, string $token)
|
||||
{
|
||||
$apiKey = config('kave.api_key');
|
||||
|
||||
if (!$apiKey) {
|
||||
throw new \Exception('KAVE_API_KEY is null');
|
||||
}
|
||||
|
||||
$url = "https://api.kavenegar.com/v1/{$apiKey}/verify/lookup.json";
|
||||
|
||||
$response = Http::timeout(5)->get($url, [
|
||||
'receptor' => $mobile,
|
||||
'token' => $token,
|
||||
'template' => config('kave.template'),
|
||||
]);
|
||||
|
||||
logger()->info('Kavenegar raw', [
|
||||
'url' => $url,
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body(),
|
||||
]);
|
||||
|
||||
return $response->json();
|
||||
}
|
||||
|
||||
}
|
||||
Regular → Executable
+10
-1
@@ -1,5 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
return [
|
||||
'url' => 'https://api.kavenegar.com/v1/' . env('KAVE_API_KEY') . '/sms/send.json'
|
||||
'base_url' => 'https://api.kavenegar.com/v1/',
|
||||
'api_key' => env('KAVE_API_KEY'),
|
||||
'template' => 'loginotp'
|
||||
];
|
||||
|
||||
|
||||
|
||||
// return [
|
||||
// 'url' => 'https://api.kavenegar.com/v1/' . env('KAVE_API_KEY') . '/verify/lookup.json'
|
||||
// ];
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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::table('users', function (Blueprint $table) {
|
||||
$table->timestamp('mobile_verified_at')->nullable()->after('mobile');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('mobile_verified_at');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -55,6 +55,8 @@
|
||||
Route::apiResource('reminders', ReminderController::class);
|
||||
});
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
Route::post('/verify-mobile/request', [UserController::class, 'requestMobileVerification']);
|
||||
Route::post('/verify-mobile/confirm', [UserController::class, 'confirmMobileVerification']);
|
||||
Route::post('profile', [UserController::class, 'updateProfile']);
|
||||
|
||||
|
||||
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Reference in New Issue
Block a user