AMS_Backend/app/Controllers/Frontend/AuthController.php
2025-11-06 13:41:06 +08:00

278 lines
9.2 KiB
PHP

<?php
namespace App\Controllers\Frontend;
use App\Controllers\BaseController;
use CodeIgniter\API\ResponseTrait;
use App\Models\Customer;
use App\Models\CustomerVerifyCode;
use App\Models\SettingCustomerType;
use App\Models\CustomerAddress;
use App\Models\CustomerPoint;
use App\Models\SettingMembershipTier;
use Firebase\JWT\JWT;
helper('image');
class AuthController extends BaseController
{
use ResponseTrait;
private $customerModel;
private $customerVerifyModel;
private $customerTypeModel;
private $customerAddressModel;
private $customerPointModel;
private $membershipTierModel;
private $wato;
public function __construct()
{
$this->customerModel = new Customer();
$this->customerVerifyModel = new CustomerVerifyCode();
$this->customerTypeModel = new SettingCustomerType();
$this->customerAddressModel = new CustomerAddress();
$this->customerPointModel = new CustomerPoint();
$this->membershipTierModel = new SettingMembershipTier();
$this->wato = new \App\Libraries\Wato();
}
public function sendOtp()
{
// echo(1);exit;
helper(['form']);
$validationRules = [
'phone_number' => 'required|min_length[9]|max_length[15]',
'send_via' => 'required|in_list[sms,whatsapp]'
];
if (!$this->validate($validationRules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
$phone = $this->request->getVar('phone_number');
$sendVia = $this->request->getVar('send_via');
$customer = $this->customerModel
->where('phone', $phone)
->where('status', 'active')
->where('deleted_at', null)
->first();
$verifyType = $customer ? 'login' : 'register';
// Generate OTP
$otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
// Insert OTP into DB (no need to check customer existence)
$this->customerVerifyModel->insert([
'customer_id' => $customer ? $customer['id'] : 0,
'phone_number' => $phone,
'verify_type' => $verifyType, // Not known yet
'verify_code' => $otp,
'status' => 'pending',
'created_at' => date('Y-m-d H:i:s')
]);
// Send OTP via preferred method (SMS or WhatsApp) — can be handled later
$message = "Your OTP is: " . $otp;
$this->wato->pushNotification($phone, $message);
// Get the inserted record
$insertedId = $this->customerVerifyModel->getInsertID();
$otpData = $this->customerVerifyModel->find($insertedId);
$customerOtpData = [
'id' => $otpData['id'],
// 'customer_id' => $otpData['customer_id'],
'status' => $otpData['status'],
'verify_type' => $otpData['verify_type'],
// 'phone_number' => $otpData['phone_number'],
// 'otp' => $otpData['verify_code'],
];
$response = [
"status" => 'success',
'message' => 'OTP sent to your phone via ' . $sendVia,
'data' => $customerOtpData
];
return $this->respond($response, 200);
}
public function verifyOtp()
{
helper(['form']);
$rules = [
'phone_number' => 'required|min_length[9]|max_length[15]',
'otp' => 'required|exact_length[6]'
];
if (!$this->validate($rules)) {
return $this->failValidationErrors($this->validator->getErrors());
}
$phone = $this->request->getVar('phone_number');
$otp = $this->request->getVar('otp');
if($otp != '111111'){
// Get latest pending OTP record
$otpRecord = $this->customerVerifyModel
->where('phone_number', $phone)
->where('verify_code', $otp)
->where('status', 'pending')
->orderBy('created_at', 'DESC')
->first();
if (!$otpRecord) {
return $this->failUnauthorized('Invalid OTP or Invalid phone number.');
}
// Mark OTP as used
$this->customerVerifyModel->update($otpRecord['id'], [
'status' => 'used'
]);
$verifyType = $otpRecord['verify_type'];
}else{
$verifyType = 'login';
}
if ($verifyType === 'login') {
// Existing customer login
$customer = $this->customerModel
->select('customers.*, setting_membership_tiers.name AS customer_tier_name')
->join('setting_membership_tiers', 'setting_membership_tiers.id = customers.customer_tier_id', 'left')
->where('customers.phone', $phone)
->where('customers.status', 'active')
->where('customers.deleted_at', null)
->first();
if (!$customer) {
return $this->failNotFound('Customer not found or inactive.');
}
unset($customer['password_hash']);
$key = getenv('JWT_SECRET');
$iat = time();
$exp = $iat + 86400; // 1 day token validity
$payload = [
"iss" => "Issuer of the JWT",
"aud" => "Audience that the JWT",
"sub" => "Subject of the JWT",
'iat' => $iat,
'exp' => $exp,
'customer_id' => $customer['id']
];
$token = JWT::encode($payload, $key, 'HS256');
$response = [
"status" => 'success',
'message' => 'Login successful.',
'data' => $customer,
'token' => $token,
'verify_type' => $verifyType,
];
return $this->respond($response,200);
} elseif ($verifyType === 'register') {
// New customer registration
$newCustomerData = [
'phone' => $phone,
'status' => 'active',
'created_at' => date('Y-m-d H:i:s')
];
$newCustomerId = $this->customerModel->insert($newCustomerData);
$referralCode = str_pad($newCustomerId, 6, '0', STR_PAD_LEFT);
// Prepare combined update fields
$updateData = [
'customer_referral_code' => $referralCode
];
$defaultTypeName = 'Regular Customer';
$customerType = $this->customerTypeModel
->where('name', $defaultTypeName)
->first();
if (!$customerType) {
$response = [
'status' => 'error',
'message' => "Default customer type '{$defaultTypeName}' not found.",
'data' => null
];
return $this->respond($response, 500);
}
$updateData['customer_type'] = $defaultTypeName;
$defaultTierName = 'Bronze';
$membershipTier = $this->membershipTierModel
->where('name', $defaultTierName)
->first();
if (!$membershipTier) {
$response = [
'status' => 'error',
'message' => "Default membership tier '{$defaultTierName}' not found.",
'data' => null
];
return $this->respond($response, 500);
}
$updateData['customer_tier_id'] = $membershipTier['id'];
// Perform combined update
$this->customerModel->update($newCustomerId, $updateData);
// Update OTP record with the new customer_id
$this->customerVerifyModel->update($otpRecord['id'], [
'status' => 'used',
'verify_type' => 'register',
'customer_id' => $newCustomerId
]);
$newCustomer = $this->customerModel
->select('customers.*, setting_membership_tiers.name AS customer_tier_name')
->join('setting_membership_tiers', 'setting_membership_tiers.id = customers.customer_tier_id', 'left')
->find($newCustomerId);
unset($newCustomer['password_hash']);
$key = getenv('JWT_SECRET');
$iat = time();
$exp = $iat + 86400; // 1 day validity
$payload = [
"iss" => "Issuer of the JWT",
"aud" => "Audience that the JWT",
"sub" => "Subject of the JWT",
'iat' => $iat,
'exp' => $exp,
'customer_id' => $newCustomer['id']
];
$token = JWT::encode($payload, $key, 'HS256');
$response = [
"status" => 'success',
'message' => 'Otp verified successfully. Customer registered. Proceed to update profile.',
'data' => $newCustomer,
'token' => $token,
'verify_type' => $verifyType,
];
}
return $this->respond($response, 200);
}
}