migrate to gtea from bistbucket
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Customer\Http\Controllers;
|
||||
|
||||
use App\Helper\RestaurantHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Traits\Authenticatable;
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Modules\Customer\Http\Requests\Auth\CustomerLoginRequest;
|
||||
use Modules\Customer\Http\Requests\Auth\ProfileUpdateRequest;
|
||||
use Modules\Customer\Models\OtpVerification;
|
||||
use Modules\Restaurant\Models\Customer;
|
||||
|
||||
class CustomerAuthController extends Controller
|
||||
{
|
||||
use Authenticatable;
|
||||
|
||||
/**
|
||||
* Step 1: Send OTP to phone (Create customer if not exists)
|
||||
*/
|
||||
public function customerLogin(CustomerLoginRequest $request)
|
||||
{
|
||||
$phone = $request->phone;
|
||||
$restaurantId = $this->getRestaurantIdFromHeader($request);
|
||||
if ($restaurantId instanceof JsonResponse) {
|
||||
return $restaurantId;
|
||||
}
|
||||
|
||||
// Check if customer already exists
|
||||
$customer = Customer::where('restaurant_id', $restaurantId)
|
||||
->where('phone', $phone)
|
||||
->first();
|
||||
|
||||
// If customer not exists, create one
|
||||
if (! $customer) {
|
||||
$customer = Customer::create([
|
||||
'name' => 'Customer '.substr($phone, -4),
|
||||
'phone' => $phone,
|
||||
'password' => Hash::make($phone), // temporary password
|
||||
'restaurant_id' => $restaurantId,
|
||||
]);
|
||||
}
|
||||
|
||||
// Generate OTP
|
||||
$otp = '1234'; // rand(100000, 999999);
|
||||
$expiryTime = now()->addMinutes(5);
|
||||
|
||||
// Save or update OTP record
|
||||
OtpVerification::updateOrCreate(
|
||||
[
|
||||
'restaurant_id' => $restaurantId,
|
||||
'phone' => $phone,
|
||||
],
|
||||
[
|
||||
'otp' => $otp,
|
||||
'expires_at' => $expiryTime,
|
||||
'updated_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
// TODO: Send OTP via SMS Gateway (mock for now)
|
||||
// Muthofun::send($phone, "Your OTP is: $otp");
|
||||
|
||||
return $this->ResponseSuccess([
|
||||
'phone' => $phone,
|
||||
'otp' => $otp, // ⚠️ remove in production
|
||||
], 'OTP sent successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Step 2: Verify OTP and Login
|
||||
*/
|
||||
public function customerOtpVerify(Request $request)
|
||||
{
|
||||
$restaurantId = $this->getRestaurantIdFromHeader($request);
|
||||
if ($restaurantId instanceof JsonResponse) {
|
||||
return $restaurantId;
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'phone' => 'required|numeric|exists:customers,phone',
|
||||
'otp' => 'required',
|
||||
]);
|
||||
|
||||
$phone = $request->phone;
|
||||
$otp = $request->otp;
|
||||
|
||||
// Fetch OTP record
|
||||
$otpRecord = OtpVerification::where('restaurant_id', $restaurantId)
|
||||
->where('phone', $phone)
|
||||
->first();
|
||||
if (! $otpRecord) {
|
||||
return $this->ResponseError([], 'Invalid phone or OTP expired.', 400);
|
||||
}
|
||||
|
||||
// Check expiry
|
||||
if (now()->greaterThan($otpRecord->expires_at)) {
|
||||
$otpRecord->update(['otp' => null]);
|
||||
|
||||
return $this->ResponseError([], 'OTP expired. Please request a new one.', 400);
|
||||
}
|
||||
|
||||
// Check OTP validity
|
||||
if ($otpRecord->otp != $otp) {
|
||||
return $this->ResponseError([], 'Invalid OTP.', 400);
|
||||
}
|
||||
|
||||
// OTP valid → Find customer
|
||||
$customer = Customer::where('restaurant_id', $restaurantId)
|
||||
->where('phone', $phone)
|
||||
->first();
|
||||
|
||||
if (! $customer) {
|
||||
return $this->ResponseError([], 'Customer not found.', 404);
|
||||
}
|
||||
|
||||
// Clear OTP after success
|
||||
$otpRecord->update(['otp' => null]);
|
||||
|
||||
// Create API token
|
||||
$tokenResult = $customer->createToken('Customer Access Token');
|
||||
|
||||
return $this->ResponseSuccess([
|
||||
'customer' => $customer,
|
||||
'access_token' => $tokenResult->accessToken,
|
||||
'expires_at' => $tokenResult->token->expires_at,
|
||||
], 'Login successful.');
|
||||
}
|
||||
|
||||
public function customerOtpSent(Request $request)
|
||||
{
|
||||
$restaurantId = $this->getRestaurantIdFromHeader($request);
|
||||
if ($restaurantId instanceof JsonResponse) {
|
||||
return $restaurantId;
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'phone' => 'required|numeric|exists:customers,phone',
|
||||
]);
|
||||
|
||||
$phone = $request->phone;
|
||||
// TODO
|
||||
$expiryTime = now()->addMinutes(15); // OTP expiry = 2 minutes
|
||||
$otp = rand(100000, 999999); // Generate random 6-digit OTP
|
||||
|
||||
// Check if an OTP record already exists for this phone
|
||||
$otpRecord = OtpVerification::where('restaurant_id', $restaurantId)
|
||||
->where('phone', $phone)
|
||||
->first();
|
||||
|
||||
if ($otpRecord) {
|
||||
// Check if existing OTP is still valid (not expired)
|
||||
if (now()->lessThan($otpRecord->expires_at)) {
|
||||
$remainingSeconds = now()->diffInSeconds($otpRecord->expires_at);
|
||||
|
||||
return $this->ResponseError([
|
||||
'remaining_seconds' => $remainingSeconds,
|
||||
], "An OTP has already been sent. Please wait {$remainingSeconds} seconds before requesting a new one.", 429);
|
||||
}
|
||||
|
||||
// OTP expired → generate and resend a new one
|
||||
$otpRecord->update([
|
||||
'otp' => $otp,
|
||||
'expires_at' => $expiryTime,
|
||||
]);
|
||||
} else {
|
||||
// No record → create a new one
|
||||
OtpVerification::create([
|
||||
'phone' => $phone,
|
||||
'otp' => $otp,
|
||||
'expires_at' => $expiryTime,
|
||||
]);
|
||||
}
|
||||
|
||||
// TODO: Replace with your SMS sending logic
|
||||
// Example: Muthofun::send($phone, "Your OTP is: $otp");
|
||||
|
||||
return $this->ResponseSuccess([
|
||||
'phone' => $phone,
|
||||
'otp' => $otp, // ⚠️ Remove in production
|
||||
'expires_at' => $expiryTime->toDateTimeString(),
|
||||
], 'OTP sent successfully.');
|
||||
}
|
||||
|
||||
public function customerProfile(Request $request)
|
||||
{
|
||||
try {
|
||||
$customer = Customer::where('id', Auth::id())->first();
|
||||
|
||||
if ($customer) {
|
||||
$permissions = $customer->role?->permissions->pluck('name')->toArray() ?? []; // Convert permissions to an array
|
||||
|
||||
$customer = [
|
||||
'id' => $customer->id,
|
||||
'name' => $customer->first_name.' '.$customer->last_name,
|
||||
'email' => $customer->email,
|
||||
'phone' => $customer->phone,
|
||||
'image' => $customer->avatar,
|
||||
'role' => $customer->role?->name ?? 'no-role-assign',
|
||||
'status' => $customer->status,
|
||||
'permissions' => $permissions,
|
||||
];
|
||||
|
||||
return $this->responseSuccess($customer, 'Profile fetched successfully.');
|
||||
} else {
|
||||
return $this->responseError([], 'Profile not found.');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return $this->responseError([], 'An error occurred while fetching the profile.');
|
||||
}
|
||||
}
|
||||
|
||||
public function customerUpdate(ProfileUpdateRequest $request)
|
||||
{
|
||||
$customer = Auth::guard('customer')->user();
|
||||
|
||||
// Get validated data
|
||||
$data = $request->validated();
|
||||
|
||||
// Avatar upload (first time + update)
|
||||
if ($request->hasFile('avatar')) {
|
||||
$data['avatar'] = fileUploader(
|
||||
'customers/',
|
||||
'png',
|
||||
$request->file('avatar'),
|
||||
$customer->avatar // old image (null for first upload)
|
||||
);
|
||||
}
|
||||
|
||||
// Fill customer data
|
||||
$customer->fill($data);
|
||||
|
||||
// Reset email verification if email changed
|
||||
if ($customer->isDirty('email')) {
|
||||
$customer->email_verified_at = null;
|
||||
}
|
||||
|
||||
$customer->save();
|
||||
|
||||
return $this->responseSuccess(
|
||||
$customer->fresh(),
|
||||
'Profile Update Successfully Done.'
|
||||
);
|
||||
}
|
||||
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
$validated = $request->validateWithBag('updatePassword', [
|
||||
'current_password' => ['required', 'current_password'],
|
||||
'password' => ['required', 'confirmed'],
|
||||
]);
|
||||
|
||||
$request->customer()->update([
|
||||
'password' => Hash::make($validated['password']),
|
||||
]);
|
||||
|
||||
return $this->ResponseSuccess([], 'Password Changes Successfully.');
|
||||
}
|
||||
|
||||
public function accountDeleted(Request $request)
|
||||
{
|
||||
$request->validateWithBag('updatePassword', [
|
||||
'current_password' => ['required', 'current_password'],
|
||||
]);
|
||||
|
||||
$request->customer()->update([
|
||||
'deleted_at' => Carbon::now(),
|
||||
]);
|
||||
|
||||
return $this->ResponseSuccess([], 'Account Delete successfully.');
|
||||
}
|
||||
|
||||
public function customerLogout(Request $request)
|
||||
{
|
||||
try {
|
||||
$result = $request->customer()->token()->revoke();
|
||||
if ($result) {
|
||||
return $this->ResponseSuccess([], 'Logout Success');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return $this->ResponseSuccess([], 'Logout Failed');
|
||||
}
|
||||
}
|
||||
|
||||
private function getRestaurantIdFromHeader(Request $request)
|
||||
{
|
||||
$domain = $request->header('X-Domain'); // Custom header key (Change if needed)
|
||||
if (! $domain) {
|
||||
return $this->responseError([], 'Domain header is missing.', 400);
|
||||
}
|
||||
|
||||
$restaurantResponse = RestaurantHelper::getRestaurantIdByDomain($domain);
|
||||
if (! $restaurantResponse['status']) {
|
||||
return $this->responseError([], $restaurantResponse['error'], 404);
|
||||
}
|
||||
|
||||
return $restaurantResponse['restaurant_id'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user