update fix deadcode, security

This commit is contained in:
baodev0
2026-09-28 08:26:29 +07:00
parent 3af59bd9c5
commit 82080b5b84
452 changed files with 4857 additions and 26289 deletions
@@ -6,9 +6,6 @@ use App\Http\Controllers\Controller;
use App\Http\Requests\CreateCustomerRequest;
use App\Http\Resources\Api\Admin\CustomerResource;
use App\Models\Customer;
use App\Models\DnsDomain;
use App\Models\DnsRecord;
use App\Models\Service;
use App\Repositories\Customer\CustomerRepositoryInterface;
use App\Repositories\Module\Domain\DomainRepositoryInterface;
use App\Services\Customer\Concerns\ResolvesCustomer;
@@ -21,12 +18,22 @@ use App\Services\Customer\CustomerServiceProvisioningService;
use App\Services\Customer\CustomerWalletService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerAccount;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerBilling;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerDomains;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerServices;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerBulkActions;
use App\Http\Controllers\Api\Admin\Customer\Concerns\ManagesCustomerNotes;
class CustomerController extends Controller
{
use ResolvesCustomer;
use ManagesCustomerAccount;
use ManagesCustomerBilling;
use ManagesCustomerDomains;
use ManagesCustomerServices;
use ManagesCustomerBulkActions;
use ManagesCustomerNotes;
public function __construct(
private readonly CustomerRepositoryInterface $customerRepository,
@@ -115,460 +122,6 @@ class CustomerController extends Controller
return response()->json(['error' => false, 'message' => 'Customer deleted successfully']);
}
public function trash(Request $request): JsonResponse
{
$perPage = min((int) $request->get('per_page', 15), 500);
$query = Customer::onlyTrashed()->with(['hosting', 'vps', 'domain']);
if ($filter = $request->get('filter')) {
$filter = trim($filter);
$query->where(function ($q) use ($filter) {
$q->where('fullname', 'LIKE', "%{$filter}%")
->orWhere('email', 'LIKE', "%{$filter}%")
->orWhere('phone', 'LIKE', "%{$filter}%");
});
}
return $this->paginatedResponse($query->paginate($perPage));
}
public function restore(string $uuid): JsonResponse
{
$this->accountService->restore($uuid);
return response()->json(['error' => false, 'message' => 'Customer restored successfully']);
}
public function forceDelete(string $uuid): JsonResponse
{
$this->accountService->forceDelete($uuid);
return response()->json(['error' => false, 'message' => 'Customer permanently deleted']);
}
public function loginAs(Request $request, string $uuid): JsonResponse
{
$code = $this->impersonationService->createLoginCode($uuid, Auth::guard('admin')->user(), $request);
return response()->json(['error' => false, 'data' => ['code' => $code]]);
}
public function resetPassword(string $uuid): JsonResponse
{
$this->mailService->resetPassword($uuid);
return response()->json([
'error' => false,
'message' => 'Password reset successfully, new password has been sent to customer email',
]);
}
public function sendPasswordEmail(Request $request, string $uuid): JsonResponse
{
$data = $request->validate(['password' => 'required|string|min:8|max:64']);
$this->mailService->sendPasswordEmail($uuid, $data['password'], $request->ip());
return response()->json(['error' => false, 'message' => 'Đã gửi mật khẩu mới cho khách hàng.']);
}
public function sendEmail(Request $request, string $uuid): JsonResponse
{
$data = $request->validate([
'template_id' => 'nullable|integer|exists:template,id',
'subject' => 'required_without:template_id|nullable|string|max:255',
'message' => 'required_without:template_id|nullable|string',
'to' => 'nullable|string|max:1000',
'cc' => 'nullable|string|max:1000',
'bcc' => 'nullable|string|max:1000',
]);
$this->mailService->sendCustomEmail($uuid, $data, Auth::guard('admin')->user(), $request->ip());
return response()->json(['error' => false, 'message' => 'Đã gửi email cho khách hàng.']);
}
public function addCredit(Request $request, string $uuid): JsonResponse
{
$request->validate(['amount' => 'required|numeric|min:1', 'action' => 'required|in:+,-']);
$this->walletService->adjustCredit(
$uuid,
Auth::guard('admin')->user(),
(int) $request->amount,
$request->action === '+',
);
return response()->json(['error' => false, 'message' => 'Credit updated successfully']);
}
public function addTotal(Request $request, string $uuid): JsonResponse
{
$data = $request->validate(['amount' => 'required|numeric|min:1', 'note' => 'required|string|max:1000']);
$admin = Auth::guard('admin')->user();
abort_if(!$admin, 401, 'Unauthorized');
$transaction = $this->walletService->addTotal($uuid, $admin, (int) $data['amount'], trim($data['note']), $request->ip());
return response()->json([
'error' => false,
'message' => 'Total updated successfully',
'data' => [
'transaction' => [
'uuid' => $transaction->uuid,
'amount' => $transaction->amount,
'note' => $transaction->note,
'admin' => $admin->username ?? $admin->email,
],
],
]);
}
public function getProducts(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->serviceProvisioning->getProducts($uuid)]);
}
public function getInvoices(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->billingService->getInvoices($uuid)]);
}
public function updateInvoice(string $uuid, int $invoiceId, Request $request): JsonResponse
{
$data = $request->validate([
'invoice_number' => 'nullable|string|max:50',
'status' => 'nullable|integer|in:1,2,3,4,5',
'payment_method' => 'nullable|in:transfer,balance',
'date' => 'nullable|date',
'due_date' => 'nullable|date',
'date_paid' => 'nullable|date',
'note' => 'nullable|string',
'sub_total' => 'nullable|integer|min:0',
'tax' => 'nullable|integer|min:0',
'total' => 'nullable|integer|min:0',
]);
$invoice = $this->billingService->updateInvoice($uuid, $invoiceId, $data);
return response()->json(['error' => false, 'message' => 'Đã cập nhật hóa đơn', 'data' => $invoice]);
}
public function getTransactions(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->billingService->getTransactions($uuid)]);
}
public function updateTransaction(string $uuid, int $transactionId, Request $request): JsonResponse
{
$data = $request->validate([
'trans' => 'nullable|string|max:255',
'note' => 'nullable|string',
'type' => 'nullable|string|max:50',
'amount' => 'nullable|integer',
]);
$transaction = $this->billingService->updateTransaction($uuid, $transactionId, $data);
return response()->json(['error' => false, 'message' => 'Đã cập nhật giao dịch', 'data' => $transaction]);
}
public function getDomains(string $uuid): JsonResponse
{
$customer = $this->resolveCustomer($uuid);
$domains = $this->moduleDomainRepository->filter(['customer_id' => $customer->id], ['customer']);
return response()->json(['error' => false, 'data' => $domains]);
}
public function getDnsDomains(string $uuid): JsonResponse
{
$customer = $this->resolveCustomer($uuid);
$domains = DnsDomain::query()
->with(['server:id,name,ip_address', 'registrar:id,name,short_name,website'])
->withCount(['ns', 'record'])
->whereHas('customer', fn($q) => $q->where('customers.id', $customer->id))
->orderByDesc('id')
->get()
->map(fn($d) => [
'id' => $d->id,
'domain_name' => $d->domain_name,
'is_created' => (int) $d->is_created,
'plesk_id' => $d->plesk_id,
'ns_count' => (int) ($d->ns_count ?? 0),
'record_count' => (int) ($d->record_count ?? 0),
'server' => $d->server ? [
'id' => $d->server->id,
'name' => $d->server->name,
'ip_address' => $d->server->ip_address,
] : null,
'registrar' => $d->registrar ? [
'id' => $d->registrar->id,
'name' => $d->registrar->name,
'short_name' => $d->registrar->short_name,
'website' => $d->registrar->website,
] : null,
'created_at' => $d->created_at,
'updated_at' => $d->updated_at,
]);
return response()->json(['error' => false, 'data' => $domains]);
}
public function getDnsDomainRecords(string $uuid, int $domainId): JsonResponse
{
$customer = $this->resolveCustomer($uuid);
$owns = DB::table('dns_domain_user')
->where('domain_id', $domainId)
->where('user_id', $customer->id)
->exists();
abort_if(!$owns, 403, 'Domain không thuộc về khách hàng này');
$records = DnsRecord::query()
->where('dns_manager_domain_id', $domainId)
->orderBy('type')
->orderBy('name')
->get();
return response()->json(['error' => false, 'data' => $records]);
}
public function getServices(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->serviceProvisioning->getServices($uuid)]);
}
public function bulkDeleteServices(string $uuid, Request $request): JsonResponse
{
$data = $request->validate(['ids' => 'required|array|min:1', 'ids.*' => 'integer']);
$deleted = $this->serviceProvisioning->bulkDeleteServices($uuid, $data['ids']);
return response()->json(['error' => false, 'message' => "Đã xoá {$deleted} dịch vụ", 'data' => ['deleted' => $deleted]]);
}
public function updateService(string $uuid, int $serviceId, Request $request): JsonResponse
{
$data = $request->validate([
'server_name' => 'nullable|string|max:255',
'status' => 'nullable|in:pending,active,suspended,expired,cancelled,terminated',
'auto_renew' => 'nullable|boolean',
'started_at' => 'nullable|date',
'expires_at' => 'nullable|date',
'note' => 'nullable|string',
'requirements' => 'nullable|string',
'feedback' => 'nullable|string',
'price' => 'nullable|numeric|min:0',
'os_id' => 'nullable|integer|exists:os,id',
'vm_cpu' => 'nullable|integer|min:1',
'vm_ram_mb' => 'nullable|integer|min:1',
'vm_disk_gb' => 'nullable|integer|min:1',
'vm_ip' => 'nullable|string|max:45',
'vm_dns' => 'nullable|string|max:100',
'vm_user' => 'nullable|string|max:255',
'vm_password' => 'nullable|string|max:255',
'vm_port' => 'nullable|integer|min:1|max:65535',
]);
$service = $this->serviceProvisioning->updateService($uuid, $serviceId, $data);
return response()->json(['error' => false, 'message' => 'Cập nhật dịch vụ thành công', 'data' => $service]);
}
public function changeServiceIp(string $uuid, int $serviceId, Request $request): JsonResponse
{
$data = $request->validate(['ip' => 'required|ip']);
abort_if(!Service::where('id', $serviceId)->value('vm_id'), 422, 'Dịch vụ chưa gắn VM.');
$service = $this->serviceProvisioning->updateService($uuid, $serviceId, ['vm_ip' => $data['ip']]);
return response()->json(['error' => false, 'message' => 'Đã đổi IP thành công', 'data' => $service]);
}
public function changeServicePort(string $uuid, int $serviceId, Request $request): JsonResponse
{
$data = $request->validate(['port' => 'required|integer|min:1|max:65535']);
abort_if(!Service::where('id', $serviceId)->value('vm_id'), 422, 'Dịch vụ chưa gắn VM.');
$service = $this->serviceProvisioning->updateService($uuid, $serviceId, ['vm_port' => $data['port']]);
return response()->json(['error' => false, 'message' => 'Đã đổi port thành công', 'data' => $service]);
}
public function notifyServiceRenewal(string $uuid, int $serviceId): JsonResponse
{
$this->serviceProvisioning->notifyRenewal($uuid, $serviceId);
return response()->json(['error' => false, 'message' => 'Đã gửi thông báo gia hạn đến khách hàng.']);
}
public function createService(string $uuid, Request $request): JsonResponse
{
$data = $request->validate([
'product_id' => 'required|integer|exists:products,id',
'virtual_machine_id' => 'nullable|integer|exists:virtual_machines,id',
'server_name' => 'nullable|string|max:255',
'status' => 'nullable|in:pending,active,suspended,expired,cancelled,terminated',
'auto_renew' => 'nullable|boolean',
'started_at' => 'nullable|date',
'expires_at' => 'nullable|date',
'note' => 'nullable|string',
'billing_cycle' => 'nullable|in:monthly,quarterly,semi_annually,annually,biennially,triennially',
'payment_method' => 'required|in:transfer,balance',
'amount_paid' => 'nullable|numeric|min:0',
'proof_images' => 'nullable|array',
'proof_images.*' => 'file|image|max:5120',
'os_id' => 'nullable|integer|exists:os,id',
'vm_cpu' => 'nullable|integer|min:1',
'vm_ram_mb' => 'nullable|integer|min:1',
'vm_disk_gb' => 'nullable|integer|min:1',
'vm_ip' => 'nullable|string|max:45',
'vm_dns' => 'nullable|string|max:100',
'vm_user' => 'nullable|string|max:255',
'vm_password' => 'nullable|string|max:255',
'vm_port' => 'nullable|integer|min:1|max:65535',
]);
// Upload proof images (chuyển khoản) — I/O ở tầng HTTP, service chỉ nhận đường dẫn đã lưu.
if ($data['payment_method'] === 'transfer' && $request->hasFile('proof_images')) {
$data['_proof_paths'] = collect($request->file('proof_images'))
->map(fn($file) => $file->store('payment-proofs', 'public'))
->all();
}
$service = $this->serviceProvisioning->createService($uuid, $data, $request->ip());
return response()->json(['error' => false, 'message' => 'Service created', 'data' => $service], 201);
}
public function listAvailableVms(Request $request): JsonResponse
{
$vms = $this->serviceProvisioning->listAvailableVms(trim((string) $request->get('q', '')));
return response()->json(['error' => false, 'data' => $vms]);
}
public function getOrders(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->billingService->getOrders($uuid)]);
}
public function updateOrder(string $uuid, int $orderId, Request $request): JsonResponse
{
$data = $request->validate([
'order_num' => 'nullable|string|max:255',
'status' => 'nullable|integer|in:0,1,2,3',
'payment_method' => 'nullable|in:transfer,balance',
'date' => 'nullable|date',
'sub_total' => 'nullable|integer|min:0',
'discount_amount' => 'nullable|integer|min:0',
'total' => 'nullable|integer|min:0',
]);
$order = $this->billingService->updateOrder($uuid, $orderId, $data);
return response()->json(['error' => false, 'message' => 'Đã cập nhật đơn hàng', 'data' => $order]);
}
public function updateStatus(string $uuid, Request $request): JsonResponse
{
$request->validate(['status' => ['required', 'integer', 'in:0,1,2,3']]);
$this->accountService->updateStatus($uuid, (int) $request->input('status'));
return response()->json(['error' => false, 'message' => 'Cập nhật trạng thái thành công']);
}
public function bulkDelete(Request $request): JsonResponse
{
$request->validate(['uuids' => ['required', 'array', 'min:1'], 'uuids.*' => ['string']]);
$count = $this->accountService->bulkDelete($request->input('uuids'));
return response()->json(['error' => false, 'message' => "Đã xoá {$count} khách hàng"]);
}
public function bulkRestore(Request $request): JsonResponse
{
$request->validate(['uuids' => ['required', 'array', 'min:1'], 'uuids.*' => ['string']]);
$count = $this->accountService->bulkRestore($request->input('uuids'));
return response()->json(['error' => false, 'message' => "Đã khôi phục {$count} khách hàng"]);
}
public function bulkForceDelete(Request $request): JsonResponse
{
$request->validate(['uuids' => ['required', 'array', 'min:1'], 'uuids.*' => ['string']]);
$count = $this->accountService->bulkForceDelete($request->input('uuids'));
return response()->json(['error' => false, 'message' => "Đã xoá vĩnh viễn {$count} khách hàng"]);
}
public function bulkStatus(Request $request): JsonResponse
{
$data = $request->validate([
'uuids' => ['required', 'array', 'min:1'],
'uuids.*' => ['string'],
'status' => ['required', 'integer', 'in:0,1,2,3'],
]);
$count = $this->accountService->bulkStatus($data['uuids'], $data['status']);
return response()->json(['error' => false, 'message' => "Đã cập nhật trạng thái {$count} khách hàng"]);
}
public function getCustomerNotes(string $uuid): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->noteService->getCustomerNotes($uuid)]);
}
public function storeCustomerNote(string $uuid, Request $request): JsonResponse
{
$data = $request->validate(['note' => 'required|string']);
$note = $this->noteService->storeCustomerNote($uuid, $data['note'], Auth::id());
return response()->json(['error' => false, 'message' => 'Đã thêm ghi chú', 'data' => $note]);
}
public function destroyCustomerNote(string $uuid, int $noteId): JsonResponse
{
$this->noteService->destroyNote($uuid, $noteId);
return response()->json(['error' => false, 'message' => 'Đã xoá ghi chú']);
}
public function getServiceNotes(string $uuid, int $serviceId): JsonResponse
{
return response()->json(['error' => false, 'data' => $this->noteService->getServiceNotes($uuid, $serviceId)]);
}
public function storeServiceNote(string $uuid, int $serviceId, Request $request): JsonResponse
{
$data = $request->validate(['note' => 'required|string']);
$note = $this->noteService->storeServiceNote($uuid, $serviceId, $data['note'], Auth::id());
return response()->json(['error' => false, 'message' => 'Đã thêm ghi chú', 'data' => $note]);
}
public function destroyServiceNote(string $uuid, int $serviceId, int $noteId): JsonResponse
{
$this->noteService->destroyNote($uuid, $noteId);
return response()->json(['error' => false, 'message' => 'Đã xoá ghi chú']);
}
private function paginatedResponse(\Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator): JsonResponse
{
return response()->json([