client api

This commit is contained in:
pbao9
2026-02-11 10:08:39 +07:00
parent 458ad0a4cb
commit d59b2a0840
27 changed files with 4369 additions and 28 deletions
@@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers\Api\Client;
use App\Http\Controllers\Controller;
use App\Http\Requests\Api\Client\ClientAuthRequest;
use App\Http\Requests\Api\Client\ClientRegisterRequest;
use App\Http\Resources\Api\Client\ClientResource;
use App\Services\Api\Client\ClientAuthService;
use Illuminate\Support\Facades\Auth;
class ClientController extends Controller
{
protected $authService;
public function __construct(ClientAuthService $authService)
{
$this->authService = $authService;
}
/**
* Lấy thông tin khách hàng hiện tại
*/
public function me()
{
return new ClientResource(auth('sanctum')->user());
}
/**
* Đăng nhập khách hàng
*/
public function login(ClientAuthRequest $request)
{
$result = $this->authService->authenticateClient($request->validated());
return response()->json([
'error' => false,
'data' => [
'client' => new ClientResource($result['client']),
'token' => $result['token'],
],
]);
}
/**
* Đăng ký khách hàng mới
*/
public function register(ClientRegisterRequest $request)
{
$result = $this->authService->registerClient($request->validated());
return response()->json([
'error' => false,
'data' => [
'client' => new ClientResource($result['client']),
'token' => $result['token'],
],
]);
}
/**
* Đăng xuất khách hàng
*/
public function logout()
{
auth('sanctum')->user()->currentAccessToken()->delete();
return response()->json([
'error' => false,
'message' => 'Đã đăng xuất thành công.',
]);
}
}
@@ -0,0 +1,51 @@
<?php
namespace App\Http\Requests\Api\Client;
use Illuminate\Foundation\Http\FormRequest;
class ClientAuthRequest extends FormRequest
{
/**
* Allow request
*/
public function authorize(): bool
{
return true;
}
/**
* Validation rules
*/
public function rules(): array
{
return [
'email' => [
'required',
'email',
'exists:customers,email'
],
'password' => [
'required',
'string',
'min:6'
],
];
}
/**
* Custom messages (optional)
*/
public function messages(): array
{
return [
'email.required' => 'Email là bắt buộc',
'email.email' => 'Email không đúng định dạng',
'email.exists' => 'Email không tồn tại',
'password.required' => 'Mật khẩu là bắt buộc',
'password.min' => 'Mật khẩu tối thiểu 6 ký tự',
];
}
}
@@ -0,0 +1,69 @@
<?php
namespace App\Http\Requests\Api\Client;
use Illuminate\Foundation\Http\FormRequest;
class ClientRegisterRequest extends FormRequest
{
/**
* Allow request
*/
public function authorize(): bool
{
return true;
}
/**
* Validation rules
*/
public function rules(): array
{
return [
'fullname' => [
'required',
'string',
'max:255'
],
'phone' => [
'required',
'digits:10',
'unique:customers,phone'
],
'email' => [
'required',
'email',
'max:255',
'unique:customers,email'
],
'password' => [
'required',
'string',
'min:6',
'confirmed'
],
];
}
/**
* Custom messages
*/
public function messages(): array
{
return [
'fullname.required' => 'Tên là bắt buộc',
'phone.required' => 'Số điện thoại là bắt buộc',
'phone.digits' => 'Số điện thoại phải có 10 chữ số',
'phone.unique' => 'Số điện thoại đã tồn tại',
'email.required' => 'Email là bắt buộc',
'email.email' => 'Email không đúng định dạng',
'email.unique' => 'Email đã tồn tại',
'password.required' => 'Mật khẩu là bắt buộc',
'password.min' => 'Mật khẩu tối thiểu 6 ký tự',
'password.confirmed' => 'Xác nhận mật khẩu không khớp',
];
}
}
@@ -22,11 +22,11 @@ class UserRegisterRequest extends FormRequest
public function rules(): array
{
return [
'email' => 'required|email|unique:customer',
'email' => 'required|email|unique:customers',
'firstname' => 'required',
'lastname' => 'required',
'password' => 'required|min:8',
'phone' => 'required|unique:customer'
'phone' => 'required|unique:customers'
];
}
@@ -24,7 +24,7 @@ class UserStoreInformation extends FormRequest
return [
'firstname' => 'required',
'lastname' => 'required',
'email' => 'nullable|email|unique:customer,email',
'email' => 'nullable|email|unique:customers,email',
'address' => 'nullable',
'phone' => 'required',
'gender' => 'nullable',
@@ -0,0 +1,63 @@
<?php
namespace App\Http\Resources\Api\Client;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ClientResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
if (!$this->resource) {
return [];
}
return [
'customer' => [
'name' => $this->fullname,
'email' => $this->email,
'phone' => $this->phone,
'address' => $this->address,
'city' => $this->city,
'ward' => $this->ward,
'province' => $this->province,
'active_phone' => 1,
'active_zalo' => 1,
'gender' => $this->gender,
'date' => $this->created_at ? $this->created_at->format('Y-m-d H:i:s') : null,
'company' => $this->company ?? '',
'mst' => null,
'avatar' => $this->avatar,
'cmnd_after' => $this->cmnd_after,
'cmnd_before' => $this->cmnd_before,
'cmnd_active' => (bool) $this->identity_number,
'cmnd' => $this->cmnd,
'fb_link' => null,
'active_2fa' => 0,
'off_mail_marketing' => $this->off_mail_marketing,
'is_recharge_zalo' => 0,
'is_verify_telegram' => 0,
],
'credit' => [
'credit' => $this->credit,
'total' => $this->total,
'point' => $this->point,
'point_used' => 0,
'point_total' => $this->point,
],
'service' => [
'vps' => $this->vps()->count(),
'proxy' => 0,
'server' => 0,
'hosting' => $this->hosting()->count(),
'domain' => $this->domain()->count(),
]
];
}
}
+63 -7
View File
@@ -2,19 +2,28 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;
class Customer extends Authenticatable
{
use HasFactory, HasApiTokens;
use HasFactory, HasApiTokens, HasUuids;
protected $table = 'customer';
protected $table = 'customers';
/**
* Chỉ định cột sẽ nhận UUID.
* Mặc định HasUuids dùng cột 'id', mình đổi sang 'uuid'.
*/
public function uniqueIds()
{
return ['uuid'];
}
protected $fillable = [
'firstname',
'lastname',
'fullname',
'avatar',
'address',
'state',
@@ -28,15 +37,26 @@ class Customer extends Authenticatable
'email_hash',
'email_marketing',
'receive_deposit',
'cccd',
'front_cccd',
'back_cccd',
'identity_number',
'front_identity_number',
'back_identity_number',
'password',
'credit',
'total',
'remember_token',
'status',
'gender',
'province_code',
'ward_code',
];
/**
* Appends for API
*/
protected $appends = [
'first_name',
'last_name',
'point',
];
/**
@@ -163,4 +183,40 @@ class Customer extends Authenticatable
{
return (bool) $this->receive_deposit;
}
public function getPointAttribute()
{
return (string) floor($this->total / 100);
}
public function getCmndBeforeAttribute()
{
return $this->front_identity_number ?? '';
}
public function getCmndAfterAttribute()
{
return $this->back_identity_number ?? '';
}
public function getCmndAttribute()
{
return $this->identity_number;
}
public function getOffMailMarketingAttribute()
{
return $this->email_marketing;
}
public function province()
{
return $this->belongsTo(Province::class, 'province_code', 'code');
}
public function ward()
{
return $this->belongsTo(Ward::class, 'ward_code', 'code');
}
}
+78
View File
@@ -0,0 +1,78 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Province extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'provinces';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'code';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'string';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'code',
'name',
'name_en',
'full_name',
'full_name_en',
'code_name',
'administrative_unit_id',
];
/**
* Get the administrative unit that owns the province.
*/
public function administrativeUnit()
{
return $this->belongsTo(AdministrativeUnit::class, 'administrative_unit_id');
}
/**
* Get the wards for the province.
*/
public function wards()
{
return $this->hasMany(Ward::class, 'province_code', 'code');
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Ward extends Model
{
use HasFactory;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'wards';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'code';
/**
* The "type" of the primary key ID.
*
* @var string
*/
protected $keyType = 'string';
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'code',
'name',
'name_en',
'full_name',
'full_name_en',
'code_name',
'province_code',
'administrative_unit_id',
];
/**
* Get the province that owns the ward.
*/
public function province()
{
return $this->belongsTo(Province::class, 'province_code', 'code');
}
/**
* Get the administrative unit that owns the ward.
*/
public function administrativeUnit()
{
return $this->belongsTo(AdministrativeUnit::class, 'administrative_unit_id');
}
}
+6
View File
@@ -359,6 +359,12 @@ class RepositoryProvider extends ServiceProvider
ProductCategoryRepositoryInterface::class,
ProductCategoryRepository::class
);
// Client API
$this->app->bind(
\App\Repositories\Api\Client\ClientRepositoryInterface::class,
\App\Repositories\Api\Client\ClientRepository::class
);
}
/**
@@ -0,0 +1,71 @@
<?php
namespace App\Repositories\Api;
use App\Repositories\BaseRepositoryInterface;
abstract class BaseApiRepository implements BaseRepositoryInterface
{
protected $model;
public function __construct()
{
$this->setModel();
}
abstract public function getModel();
protected function setModel()
{
$this->model = app()->make($this->getModel());
return $this;
}
public function create(array $data = [])
{
return $this->model->create($data);
}
public function getAll()
{
return $this->model->all();
}
public function find($id)
{
return $this->model->find($id);
}
public function insert(array $data = [])
{
return $this->model->insert($data);
}
public function update(int $id = 0, array $data = [])
{
$result = $this->find($id);
if ($result) {
$result->update($data);
return $result;
}
return false;
}
public function delete($id)
{
$result = $this->find($id);
if ($result) {
$result->delete();
return true;
}
return false;
}
public function getCount()
{
return $this->model->count('id');
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Repositories\Api\Client;
use App\Models\Customer;
use App\Repositories\Api\BaseApiRepository;
class ClientRepository extends BaseApiRepository implements ClientRepositoryInterface
{
public function getModel()
{
return Customer::class;
}
/**
* Tìm khách hàng theo email
*/
public function findByEmail(string $email)
{
return $this->model->where('email', $email)->first();
}
}
@@ -0,0 +1,13 @@
<?php
namespace App\Repositories\Api\Client;
use App\Repositories\BaseRepositoryInterface;
interface ClientRepositoryInterface extends BaseRepositoryInterface
{
/**
* Tìm khách hàng theo email
*/
public function findByEmail(string $email);
}
@@ -0,0 +1,57 @@
<?php
namespace App\Services\Api\Client;
use App\Repositories\Api\Client\ClientRepositoryInterface;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class ClientAuthService
{
protected $clientRepository;
public function __construct(ClientRepositoryInterface $clientRepository)
{
$this->clientRepository = $clientRepository;
}
/**
* Xác thực khách hàng và tạo token
*/
public function authenticateClient(array $credentials): array
{
if (!Auth::guard('client')->attempt($credentials)) {
throw ValidationException::withMessages([
'email' => ['Thông tin đăng nhập không chính xác.'],
]);
}
$client = Auth::guard('client')->user();
$token = $client->createToken('client-token')->plainTextToken;
return [
'client' => $client,
'token' => $token,
];
}
/**
* Đăng ký khách hàng mới và tạo token
*/
public function registerClient(array $data): array
{
$client = $this->clientRepository->create([
'fullname' => $data['fullname'],
'phone' => $data['phone'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$token = $client->createToken('client-token')->plainTextToken;
return [
'client' => $client,
'token' => $token,
];
}
}
@@ -0,0 +1,7 @@
<?php
namespace app\Services\Api\Client;
class ClientService{
}