Files
portal-api/routes/api.php
T
2026-02-10 16:49:59 +07:00

1551 lines
74 KiB
PHP

<?php
use App\Http\Controllers\rest\ModuleController;
use App\Http\Services\Media;
use App\Http\Services\vCenter as ServiceVCenter;
use App\Jobs\Hosting\CreateHostingJobs;
use App\Jobs\VirtualMachine\Create\CreateVMJobs;
use App\Jobs\VirtualMachine\Upgrade\UpgradeVirtualMachine;
use App\Models\Addon;
use App\Models\Customer;
use App\Models\File;
use App\Models\Hosting;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\ModuleDatacenter;
use App\Models\ModuleHost;
use App\Models\ModuleHosting;
use App\Models\ModuleHostingServer;
use App\Models\ModuleIpAddress;
use App\Models\ModuleSnapshot;
use App\Models\ModuleVmware;
use App\Models\Os;
use App\Models\OsGroup;
use App\Models\Type;
use App\Models\vCenter;
use App\Models\VPS;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::get('/', fn() => response()->json(['api' => 'ok']));
Route::prefix('v1')
/* Api for Admin */
->group(function () {
Route::prefix('system')->middleware(['auth:sanctum'])->group(function () {
Route::controller(ModuleController::class)->group(function () {
Route::get('get-list-vcenter', 'getVCenter')->name('api.getVCenter');
Route::get('get-list-datacenter', 'getDatacenter')->name('api.getDatacenter');
Route::get('get-list-host', 'getHost')->name('api.getHost');
Route::get('get-list-datastore', 'getDatastore')->name('api.getDatastore');
Route::get('get-list-network', 'getNetwork')->name('api.getNetwork');
Route::get('get-list-ipaddress', 'getIpAddress')->name('api.getIPAddress');
Route::get('get-list-version-os', 'getOsServerVersion')->name('api.getVersion');
Route::get('get-list-os-group', 'getOsGroup')->name('api.getOsGroup');
});
Route::get('test-ssh-connection', function (ServiceVCenter $serviceVCenter) {
Log::info('🧪 API Test SSH Connection - Starting test via route');
return response()->json($serviceVCenter->testSSHConnection());
})->name('api.testSSHConnection');
Route::post('rebuild-vps', [\App\Http\Controllers\Api\VpsActionController::class, 'rebuildVps'])
->name('api.system.rebuildVps');
Route::get('get-list-product', function () {
$type_id = \request()->get('type');
if (!$type_id) {
return response()->json(['error' => true, 'message' => 'Please choose Type']);
}
if ($type_id === 1 || $type_id === 2) {
return response()->json(['error' => true, 'message' => 'Not Found']);
}
$model = null;
switch ($type_id) {
case 3:
$model = Hosting::select('id', 'name', 'price', 'price_sale')->get();
break;
case 4:
$model = VPS::select('id', 'name', 'price', 'price_sale', 'module_host_id')->get();
break;
default:
break;
}
if (!$model) {
return response()->json(['error' => true, 'message' => 'Not Found']);
}
return response()->json(['error' => false, 'data' => $model->all()]);
})->name('api.getProduct');
Route::get('get-list-product-type', function () {
$type = Type::select('id', 'name')->get();
return response()->json(['error' => false, 'data' => $type->all()]);
})->name('api.getProductType');
Route::get('get-ticket-console', function (Request $request, ServiceVCenter $serviceVCenter) {
$product_id = $request->get('product');
if (!$product_id) {
return response()->json(['error' => true, 'message' => "Please choose product"]);
}
$product = ModuleVmware::with('ipAddress.host.datacenter.vCenter')->find($product_id);
if (!$product) {
return response()->json(['error' => true, 'message' => "Can't find product"]);
}
$vcenter = null;
if ($product->ipAddress && $product->ipAddress->host && $product->ipAddress->host->datacenter && $product->ipAddress->host->datacenter->vCenter) {
$vcenter = $product->ipAddress->host->datacenter->vCenter;
}
if (!$vcenter) {
return response()->json(['error' => true, 'message' => "Can't find vCenter information"]);
}
// Đăng nhập vCenter trước khi lấy ticket
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
]);
}
$ConsoleTicket = $serviceVCenter->GetConsoleTickets($product->vmware_id);
// Nếu login hết hạn, thử login lại 1 lần nữa
if ($ConsoleTicket === 'Login_Again') {
if ($serviceVCenter->loginServer($vcenter)) {
$ConsoleTicket = $serviceVCenter->GetConsoleTickets($product->vmware_id);
} else {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập lại vào vCenter'
]);
}
}
// Nếu vẫn lỗi, trả về lỗi rõ ràng
if (is_string($ConsoleTicket)) {
return response()->json([
'error' => true,
'message' => "Failed to get console ticket: $ConsoleTicket"
]);
}
if ($ConsoleTicket['error']) {
return response()->json([
'error' => true,
'message' => $ConsoleTicket['data']
]);
}
return response()->json([
'error' => false,
'data' => $ConsoleTicket['data'],
'host' => $vcenter->host,
'vmware-api-session-id' => $serviceVCenter->token
])->cookie('vmware-api-session-id', $serviceVCenter->token, 60, '/', null, false, false);
})->name('api.GetConsoleTicket');
Route::get('get-version-os', function () {
$group_id = \request()->get('group');
if (!$group_id) {
return response()->json(['error' => true, 'message' => 'Please choose Host']);
}
$group_os = OsGroup::find($group_id);
if (!$group_os) {
return response()->json(['error' => true, 'message' => 'Can\'t find Group Os']);
}
$os = Os::where('os_group_id', $group_id)->select('id', 'version')->get();
if ($os->count()) {
$os = array_map(function ($array) {
$array['name'] = $array['version'];
unset($array['version']);
return $array;
}, $os->all());
return response()->json(['error' => false, 'data' => $os]);
}
return response()->json(['error' => true, 'message' => 'Can\'t find Os by Os Group ID #' . $group_id]);
})->name('api.GetVersionOs');
Route::post('get-all-image', function (Media $media) {
$files = $media->getAllMedia();
$data = view('administrator.pages.component.media')->with('media', $files)->render();
return response()->json(['data' => $data]);
})->name('api.GetAllImage');
Route::get('get-list-addon', function () {
$product = request()->input('product');
if (!$product) {
return response()->json(['error' => true, 'data' => 'Yêu cầu không hợp lệ']);
}
$allAddon = Addon::get();
$formAddon = view('administrator.pages.component.addon')->with([
'addon' => $allAddon
])->render();
return response()->json(['error' => false, 'data' => $formAddon]);
})->name('api.GetAddonProduct');
Route::post('add-addon-to-product', function (Request $request) {
$order = $request->order;
$product = $request->product;
$cpu = $request->cpu;
$ram = $request->ram;
$ssd = $request->ssd;
if (!$cpu && !$ram && !$ssd) {
return response()->json(['error' => true, 'message' => 'Invalid Request']);
}
if (!$product) {
return response()->json(['error' => true, 'message' => 'Invalid Request']);
}
$product = ModuleVmware::find($request->product);
if (!$product) {
return response()->json(['error' => true, 'message' => 'Invalid Request']);
}
if ($order && $order != $product->order_id) {
return response()->json(['error' => true, 'message' => 'Invalid Request']);
}
$invoice_id = 0;
$billing_sw = 0;
$order = \App\Models\Order::with('OrderItem')->find($product->order_id);
if ($order && $order->OrderItem) {
$order_item = $order->OrderItem->first();
$invoice_id = $order_item->invoice_id;
$billing_sw = $order_item->billing;
}
$invoice = Invoice::find($invoice_id);
if (!$invoice) {
return response()->json(['error' => true, 'message' => 'Invalid Request']);
}
$addon = [];
$item = [];
$total = 0;
if ($cpu) {
$item['cpu'] = $cpu;
}
if ($ram) {
$item['ram'] = $ram;
}
if ($ssd) {
$item['ssd'] = $ssd;
}
foreach ($item as $key => $value) {
$addonItem = Addon::where('name', 'like', "%$key%")->first();
$message = "Addon " . strtoupper($key);
switch ($billing_sw) {
case 2:
$billing = 1;
$message .= " ( " . Carbon::today()->format('d/m/Y') . " - " . Carbon::now()->addMonths(1)->format('d/m/Y') . " )";
break;
case 3:
$billing = 3;
$message .= " ( " . Carbon::today()->format('d/m/Y') . " - " . Carbon::now()->addMonths(3)->format('d/m/Y') . " )";
break;
case 4:
$billing = 6;
$message .= " ( " . Carbon::today()->format('d/m/Y') . " - " . Carbon::now()->addMonths(6)->format('d/m/Y') . " )";
break;
case 5:
$billing = 12;
$message .= " ( " . Carbon::today()->format('d/m/Y') . " - " . Carbon::now()->addMonths(12)->format('d/m/Y') . " )";
break;
}
$addon[] = [
'customer_id' => $product->customer_id,
'type_id' => 1,
'due_date' => Carbon::now()->hour(23)->minute(59)->second(59)->timestamp,
'product_id' => $addonItem->id,
'parent_id' => $product->id,
'relid' => 0,
'description' => $message,
'invoice_type' => "1",
'billing' => $billing_sw,
'amount' => $addonItem->price * $value * $billing,
'tax' => 1,
];
$total += $addonItem->price * $value * $billing;
}
try {
DB::beginTransaction();
if ($order !== 0) {
$order->increment('amount', ($total + (0.1 * $total)));
$invoice->increment('total', ($total + (0.1 * $total)));
$invoice->increment('tax', 0.1 * $total);
$invoice->increment('sub_total', $total);
$product->increment('first_payment', $total);
$product->increment('next_payment', $total);
$allAddon = array_map(function ($item) use ($invoice) {
$item['invoice_id'] = $invoice->id;
return $item;
}, $addon);
InvoiceItem::insert($allAddon);
$addonInsert = InvoiceItem::select('id')->latest('id')->take(count($allAddon))->get();
foreach ($addonInsert as $item) {
DB::table('order__order_item')->insert([
'order_id' => $order->id,
'InvoiceItem_id' => $item->id
]);
}
} else {
$invoice_added = Invoice::insertGetId([
'date' => Carbon::now()->timestamp,
'due_date' => $product->next_due_date,
'sub_total' => $total,
'tax' => $total * 0.1,
'total' => $total + ($total * 0.1),
'payment_id' => 1,
'customer_id' => $product->customer_id,
'invoice_type' => 1,
'status' => 0
]);
$order_id = \App\Models\Order::insertGetId([
'order_num' => App\Http\Helpers\Helper::generateUniqueCode(),
'customer_id' => $product->customer_id,
'user_id' => $request->user()->id,
'date' => Carbon::now()->timestamp,
'payment_id' => 1,
'invoice_id' => $invoice_added,
'amount' => $total + ($total * 0.1),
'client_ip' => $request->getClientIp(),
'status' => 0
]);
$allAddon = array_map(function ($item) use ($invoice_added) {
$item['invoice_id'] = $invoice_added;
return $item;
}, $addon);
InvoiceItem::insert($allAddon);
$addonInsert = InvoiceItem::select('id')->latest('id')->take(count($allAddon))->get();
foreach ($addonInsert as $item) {
DB::table('order__order_item')->insert([
'order_id' => $order_id,
'InvoiceItem_id' => $item->id
]);
}
}
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
return response()->json(['error' => true, 'message' => $exception->getMessage()]);
}
return response()->json(['error' => false, 'message' => 'Added Addon to Product Successfully']);
})->name('api.AcceptAddon');
Route::post('create-slug', function (Request $request) {
return Str::slug($request->get('name'));
})->name('api.CreateSlug');
Route::post('get-service-product', function (Request $request) {
$validate = Validator::make(
$request->all(),
[
'host' => 'required|numeric'
]
);
if ($validate->failed()) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$host = ModuleHost::with('Datacenter.vCenter')->find($request->host);
if (!$host) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$datacenter = ModuleDatacenter::where('vcenter_id', $host->Datacenter->vcenter_id)->select(
'id',
'name'
)->get();
$allHost = ModuleHost::where('module_datacenter_id', $host->module_datacenter_id)->select(
'id',
'name'
)->get();
$vcenter = vCenter::select('id', 'host')->get();
return response()->json([
'error' => false,
'data' => [
'host' => $allHost,
'datacenter' => $datacenter,
'vcenter' => $vcenter,
'choose' => [
'datacenter' => $host->module_datacenter_id,
'vcenter' => $host->Datacenter->vcenter_id,
'host' => $request->host
]
]
]);
})->name('api.GetServiceProduct');
Route::post('update-file-customer', function (Request $request) {
$validate = Validator::make(
$request->all(),
[
'user_id' => 'required|numeric',
'file' => 'required|string'
]
);
if ($validate->failed()) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$user = Customer::find($request->user_id);
if (!$user) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$fileName = str_replace(env('APP_URL') . '/uploads/files/', '', $request->file);
$file = File::insertGetId([
'filename' => $fileName,
'file_url' => $request->file,
'customer_id' => $request->user_id
]);
if ($file) {
return response()->json(['error' => false, 'message' => 'New file updated successfully']);
}
return response()->json(['error' => true, 'message' => 'Invalid request']);
})->name('api.CustomerUpdateFile');
Route::post('remove-file-customer', function (Request $request) {
$validate = Validator::make(
$request->all(),
[
'file' => 'required|numeric'
]
);
if ($validate->failed()) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$file = File::find($request->file);
if (!$file) {
return response()->json(['error' => true, 'message' => 'Invalid request']);
}
$file->delete();
return response()->json(['error' => false, 'message' => 'The request was processed successfully']);
})->name('api.CustomerRemoveFile');
});
})
/* Api for customer */
->group(function () {
Route::middleware(['auth:sanctum'])
->group(function () {
Route::post('get-status-virtual-machine', function (Request $request, ServiceVCenter $serviceVCenter) {
$vmware_id = $request->vmware_id;
$product_id = $request->product_id;
if (!$vmware_id || !$product_id) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$product = ModuleVmware::with('ipAddress.host.datacenter.vCenter')->find($product_id);
if (!$product) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
if ($vmware_id != $product->vmware_id) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
if ($product->status == 4) {
return response()->json(['error' => false, 'message' => 'Dịch vụ hết hạn', 'expiry' => true]);
}
if ($product->status == 3) {
return response()->json([
'error' => false,
'message' => 'Đang khởi tạo',
'expiry' => false,
'pending' => true
]);
}
$serviceVCenter->token = $product->ipAddress->host->datacenter->vCenter->token;
$serviceVCenter->apiUri = $product->ipAddress->host->datacenter->vCenter->host;
$VirtualMachine = $serviceVCenter->CheckVirtualMachine($vmware_id);
if ($VirtualMachine === 'Login_Again') {
$token = $serviceVCenter->loginServer($product->ipAddress->host->datacenter->vCenter);
if ($token) {
vCenter::where(
'id',
$product->ipAddress->host->datacenter->vCenter->id
)->update(['token' => $token]);
$serviceVCenter->token = $token;
}
$VirtualMachine = $serviceVCenter->CheckVirtualMachine($vmware_id);
}
// Check if VirtualMachine is still a string (Login_Again or other error)
if (is_string($VirtualMachine)) {
return response()->json(['error' => true, 'message' => "Failed to check virtual machine: $VirtualMachine"]);
}
if ($VirtualMachine['error']) {
return response()->json(['error' => true, 'message' => $VirtualMachine['message']]);
}
$status = 3;
if ($VirtualMachine['data']['state'] === 'RUNNING') {
$product->update([
'status' => 1
]);
}
if ($VirtualMachine['data']['state'] === 'NOT_RUNNING') {
$product->update([
'status' => 0
]);
}
$product = ModuleVmware::find($product_id);
$data = view('form.action')->with([
'user' => $request->user('')->id,
'item' => $product
])->render();
return response()->json([
'error' => false,
'message' => $VirtualMachine['data'],
'expiry' => false,
'data' => $data
]);
})->name('api.GetVirtualMachineStatus');
Route::get('get-list-group-os', function () {
$host_id = \request()->get('host');
if (!$host_id) {
return response()->json(['error' => true, 'message' => 'Please choose Host']);
}
$host = ModuleHost::find($host_id);
if (!$host) {
return response()->json(['error' => true, 'message' => 'Can\'t find Host']);
}
$osGroup = OsGroup::where('ModuleHost_id', $host_id)->select('id', 'name')->get();
if ($osGroup->count()) {
return response()->json(['error' => false, 'data' => $osGroup->all()]);
}
return response()->json([
'error' => true,
'message' => 'Can\'t find OsGroup by Host ID #' . $host_id
]);
})->name('api.user.getOsGroup');
Route::get('get-list-version-os', function () {
$group_id = \request()->get('group');
if (!$group_id) {
return response()->json(['error' => true, 'message' => 'Please choose Host']);
}
$group_os = OsGroup::find($group_id);
if (!$group_os) {
return response()->json(['error' => true, 'message' => 'Can\'t find Group Os']);
}
$os = Os::where('os_group_id', $group_id)->select('id', 'version')->get();
if ($os->count()) {
$os = array_map(function ($array) {
$array['name'] = $array['version'];
unset($array['version']);
return $array;
}, $os->all());
return response()->json(['error' => false, 'data' => $os]);
}
return response()->json([
'error' => true,
'message' => 'Can\'t find Os by Os Group ID #' . $group_id
]);
})->name('api.user.GetVersionOs');
Route::get('list-snapshot', function () {
$product_id = request()->input('product');
$user_id = request()->input('user');
if (!$product_id || !$user_id) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$snapshot = ModuleSnapshot::where(function ($query) use ($product_id, $user_id) {
$query->where('customer_id', $user_id);
$query->where('ModuleVmware_id', $product_id);
})->get();
$data = view('form.snapshot')->with([
'snapshot' => $snapshot,
'user' => $user_id,
'product' => $product_id
])->render();
return response()->json(['error' => false, 'data' => $data]);
})->name('api.user.GetSnapshot');
Route::get('get-list-addon', function () {
$product = request()->input('product');
if (!$product) {
return response()->json(['error' => true, 'data' => 'Yêu cầu không hợp lệ']);
}
$billing = InvoiceItem::select('billing')
->where('type_id', 4)
->where('relid', $product)->first();
if (!$billing) {
return response()->json(['error' => true, 'data' => 'Yêu cầu không hợp lệ']);
}
$allAddon = Addon::get();
$formAddon = view('form.upgrade')->with([
'addon' => $allAddon,
'billing' => $billing->billing,
'product' => $product
])->render();
return response()->json(['error' => false, 'data' => $formAddon]);
})->name('api.user.GetAddonProduct');
Route::post('payment-invoice', function () {
$invoice_id = \request()->input('invoice');
if (!$invoice_id) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$invoice = Invoice::with('Order', 'InvoiceItem')->find($invoice_id);
if (!$invoice) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
if ($invoice->status == 1) {
return response()->json(['error' => true, 'message' => 'Hoá đơn đã được thanh toán!']);
}
$customer = Customer::find(auth()->id());
if (!$customer) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
if ($customer->credit < $invoice->total) {
return response()->json([
'error' => true,
'message' => 'Tài khoản của quý khách không đủ để thực hiện thanh toán'
]);
}
$products = [];
$next_due_date = 0;
$next_invoice = 0;
if ($invoice->InvoiceItem->count()) {
foreach ($invoice->InvoiceItem->where('relid', '<>', 0) as $item) {
$product = $item->GetRelidProduct();
$products[] = $product;
$time = $product->next_due_date;
switch ($item->billing) {
case 2:
$next_due_date = Carbon::parse($time)->addMonths(1)->timestamp;
$next_invoice = Carbon::parse($time)->addMonths(1)->timestamp;
break;
case 3:
$next_due_date = Carbon::parse($time)->addMonths(3)->timestamp;
$next_invoice = Carbon::parse($time)->addMonths(3)->timestamp;
break;
case 4:
$next_due_date = Carbon::parse($time)->addMonths(6)->timestamp;
$next_invoice = Carbon::parse($time)->addMonths(6)->timestamp;
break;
case 5:
$next_due_date = Carbon::parse($time)->addMonths(12)->timestamp;
$next_invoice = Carbon::parse($time)->addMonths(12)->timestamp;
break;
}
}
}
try {
DB::beginTransaction();
$customer->update([
'credit' => ($customer->credit - $invoice->total)
]);
$invoice->update([
'status' => 1,
'date_paid' => time()
]);
$order = $invoice->Order;
$jobs = [];
if ($order && $order->status !== 1 && $invoice->invoice_type == 1) {
$order->update([
'status' => 1
]);
$addon = [];
$product = 0;
foreach (
$order->OrderItem->where('parent_id', 0)->whereIn(
'type_id',
[3, 4]
) as $key => $item
) {
if ($item->type_id == 3) {
$Server = ModuleHostingServer::where('status', 1)->first();
ModuleHosting::find($item->relid)->update(['module_server_id' => $Server->id]);
$jobs[] = new CreateHostingJobs($item->relid);
} else {
$product = $item->GetRelidProduct();
$os = Os::with('OsGroup')->find($product->os_id);
if ($os && $os->OsGroup) {
$ipaddress = ModuleIpAddress::where(
'ModuleHost_id',
$os->OsGroup->ModuleHost_id
)->where('status', 0)->first();
if ($ipaddress) {
$product->update([
'ModuleIpAddress_id' => $ipaddress->id
]);
$ipaddress->update([
'status' => 1
]);
$jobs[] = new CreateVMJobs($product->id);
}
}
}
}
foreach ($order->OrderItem as $item) {
if ($item->type_id == 1) {
$itemData = $item->GetItemProduct();
$price = 0;
switch ($item->billing) {
case 2:
$price = $item->amount / 1;
break;
case 3:
$price = $item->amount / 3;
break;
case 4:
$price = $item->amount / 6;
break;
case 5:
$price = $item->amount / 12;
break;
}
$addon[strtolower($itemData->name)] = (int) $price / $itemData->price;
$product = $item->parent_id;
}
}
if ($order->OrderItem->count() === count($addon)) {
dispatch(new UpgradeVirtualMachine(
$product,
$addon,
$order->id
))->delay(now()->addSeconds(10));
}
} else {
foreach ($products as $item) {
if (isset($item->vmware_id)) {
$jobs[] = new \App\Jobs\VirtualMachine\Action\VMJobs($item->id, 'Start', true);
}
if (isset($item->server_domain_id)) {
$jobs[] = new \App\Jobs\Hosting\HostingJobs($item->id, 'Activate');
}
$item->update([
'next_due_date' => $next_due_date,
'next_invoice' => $next_invoice
]);
}
}
if (count($jobs)) {
foreach ($jobs as $item) {
dispatch($item)->delay(now()->addSeconds(10));
}
}
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
return response()->json(['error' => true, 'message' => $exception->getMessage()]);
}
return response()->json(['error' => false, 'message' => "Thanh toán hoá đơn thành công"]);
})->name('api.user.PaymentInvoice');
Route::post('renew-services', function () {
$product_id = \request()->input('product');
$type_id = \request()->input('type');
$billing = \request()->input('billing');
if (!$product_id || !$type_id || !$billing) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$product = null;
switch ($type_id) {
case 3:
$product = ModuleHosting::find($product_id);
break;
case 4:
$product = ModuleVmware::find($product_id);
break;
}
if (!$product) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$customer = Customer::find(auth()->id());
if (!$customer) {
return response()->json(['error' => true, 'message' => 'Yêu cầu không hợp lệ']);
}
$item = InvoiceItem::where(function ($query) use ($product_id, $type_id) {
$query->where('invoice_type', 1);
$query->where(function ($_query) use ($product_id) {
$_query->where('relid', $product_id);
$_query->Orwhere('parent_id', $product_id);
});
if ($type_id == 4) {
$query->whereIn('type_id', [1, 4]);
} else {
$query->where('type_id', $type_id);
}
})->get();
$nextPay = (int) $product->next_payment;
$renew_item = [];
if ($item->count()) {
foreach ($item as $key => $_item) {
$renew_item[$key] = $_item->replicate();
$subMessage = '';
switch ((int) $billing) {
case 2:
$subMessage = " ( " . Carbon::parse($product->next_due_date)->format('d/m/Y') . " - " . Carbon::parse($product->next_due_date)->addMonths(1)->format('d/m/Y') . " )";
break;
case 3:
$subMessage = " ( " . Carbon::parse($product->next_due_date)->format('d/m/Y') . " - " . Carbon::parse($product->next_due_date)->addMonths(3)->format('d/m/Y') . " )";
break;
case 4:
$subMessage = " ( " . Carbon::parse($product->next_due_date)->format('d/m/Y') . " - " . Carbon::parse($product->next_due_date)->addMonths(6)->format('d/m/Y') . " )";
break;
case 5:
$subMessage = " ( " . Carbon::parse($product->next_due_date)->format('d/m/Y') . " - " . Carbon::parse($product->next_due_date)->addMonths(12)->format('d/m/Y') . " )";
break;
}
$renew_item[$key]->invoice_type = 0;
$renew_item[$key]->description = $_item->GetItemProduct()->name . $subMessage;
$renew_item[$key]->billing = $billing;
}
}
switch ((int) $billing) {
case 2:
$nextPay *= 1;
break;
case 3:
$nextPay *= 3;
break;
case 4:
$nextPay *= 6;
break;
case 5:
$nextPay *= 12;
break;
}
$date_exp = Carbon::now()->diffInDays(Carbon::parse($product->next_due_date), false);
$invoice_data = [
'date' => Carbon::now()->timestamp,
'due_date' => $date_exp > 0 ? $product->next_due_date : Carbon::now()->timestamp,
'payment_id' => 1,
'sub_total' => $nextPay,
'tax' => $nextPay * (10 / 100),
'total' => $nextPay + ($nextPay * (10 / 100)),
'invoice_type' => 0,
'customer_id' => $product->customer_id,
'status' => 0
];
try {
DB::beginTransaction();
$invoice_id = Invoice::insertGetId($invoice_data);
foreach ($renew_item as $item) {
$item->invoice_id = $invoice_id;
$item->save();
}
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
return response()->json(['error' => true, 'message' => $exception->getMessage()]);
}
return response()->json([
'error' => false,
'message' => "Yêu cầu gia hạn được xử lý thành công. Vui lòng thanh toán hoá đơn để hoàn tất!"
]);
})->name('api.user.RenewService');
Route::get('get-ticket-console', function (Request $request, ServiceVCenter $serviceVCenter) {
$product_id = $request->get('product');
if (!$product_id) {
return response()->json(['error' => true, 'message' => "Please choose product"]);
}
$product = ModuleVmware::with('ipAddress.host.datacenter.vCenter')->find($product_id);
if (!$product) {
return response()->json(['error' => true, 'message' => "Can't find product"]);
}
// Validate that the product belongs to the authenticated user
if ($product->customer_id != user()->id) {
return response()->json([
'error' => true,
'message' => 'Không có quyền truy cập máy ảo này'
]);
}
// Check if service is expired
if ($product->status == 4) {
return response()->json(['error' => true, 'message' => 'Dịch vụ đã hết hạn']);
}
// Check if VM is still initializing
if ($product->status == 3) {
return response()->json(['error' => true, 'message' => 'Máy ảo đang khởi tạo']);
}
$vcenter = null;
if ($product->ipAddress && $product->ipAddress->host && $product->ipAddress->host->datacenter && $product->ipAddress->host->datacenter->vCenter) {
$vcenter = $product->ipAddress->host->datacenter->vCenter;
}
if (!$vcenter) {
return response()->json(['error' => true, 'message' => "Can't find vCenter information"]);
}
// Đăng nhập vCenter trước khi lấy ticket
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
]);
}
$ConsoleTicket = $serviceVCenter->GetConsoleTickets($product->vmware_id);
// Nếu login hết hạn, thử login lại 1 lần nữa
if ($ConsoleTicket === 'Login_Again') {
if ($serviceVCenter->loginServer($vcenter)) {
$ConsoleTicket = $serviceVCenter->GetConsoleTickets($product->vmware_id);
} else {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập lại vào vCenter'
]);
}
}
// Nếu vẫn lỗi, trả về lỗi rõ ràng
if (is_string($ConsoleTicket)) {
return response()->json([
'error' => true,
'message' => "Failed to get console ticket: $ConsoleTicket"
]);
}
if ($ConsoleTicket['error']) {
return response()->json([
'error' => true,
'message' => $ConsoleTicket['data']
]);
}
return response()->json([
'error' => false,
'data' => $ConsoleTicket['data'],
'host' => $vcenter->host,
'vmware-api-session-id' => $serviceVCenter->token
])->cookie('vmware-api-session-id', $serviceVCenter->token, 60, '/', null, false, false);
})->name('api.user.GetConsoleTicket');
Route::post('start-virtual-machine', function (Request $request, ServiceVCenter $serviceVCenter) {
$vm_id = $request->input('vm_id') ?: $request->json('vm_id');
if (!$vm_id) {
$jsonData = json_decode($request->getContent(), true);
$vm_id = $jsonData['vm_id'] ?? null;
}
if (!$vm_id) {
return response()->json([
'error' => true,
'message' => 'Yêu cầu không hợp lệ - vm_id không được tìm thấy',
]);
}
$vm = ModuleVmware::where('vmware_id', $vm_id)->first();
if (!$vm) {
$vm = ModuleVmware::where('id', $vm_id)->first();
}
if (!$vm) {
$allVMs = ModuleVmware::where('vmware_id', 'like', '%' . $vm_id . '%')
->orWhere('id', 'like', '%' . $vm_id . '%')
->get();
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin máy ảo',
'debug' => [
'vm_id_received' => $vm_id,
'similar_vms_count' => $allVMs->count(),
'similar_vms' => $allVMs->toArray()
]
]);
}
if ($vm->customer_id != user()->id) {
return response()->json([
'error' => true,
'message' => 'Không có quyền truy cập máy ảo này'
]);
}
if ($vm->status == 4) {
return response()->json(['error' => true, 'message' => 'Dịch vụ đã hết hạn']);
}
if ($vm->status == 3) {
return response()->json(['error' => true, 'message' => 'Máy ảo đang khởi tạo']);
}
$vcenter = null;
if ($vm->ipAddress && $vm->ipAddress->host && $vm->ipAddress->host->datacenter && $vm->ipAddress->host->datacenter->vCenter) {
$vcenter = $vm->ipAddress->host->datacenter->vCenter;
}
if (!$vcenter) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin vCenter'
]);
}
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
]);
}
$result = $serviceVCenter->StartVirtualMachine($vm_id);
if ($result === "Login_Again") {
if ($serviceVCenter->loginServer($vcenter)) {
$result = $serviceVCenter->StartVirtualMachine($vm_id);
} else {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập lại vào vCenter'
]);
}
}
// Check if result is still a string (Login_Again or other error)
if (is_string($result)) {
return response()->json(['error' => true, 'message' => "Failed to start virtual machine: $result"]);
}
if ($result['error']) {
return response()->json(['error' => true, 'message' => $result['data']]);
}
$vm->update(['status' => 1]);
return response()->json([
'error' => false,
'message' => 'Khởi động máy ảo thành công'
]);
})->name('api.user.StartVirtualMachine');
Route::post('stop-virtual-machine', function (Request $request, ServiceVCenter $serviceVCenter) {
$vm_id = $request->input('vm_id') ?: $request->json('vm_id');
if (!$vm_id) {
$jsonData = json_decode($request->getContent(), true);
$vm_id = $jsonData['vm_id'] ?? null;
}
if (!$vm_id) {
return response()->json([
'error' => true,
'message' => 'Yêu cầu không hợp lệ - vm_id không được tìm thấy'
]);
}
$vm = ModuleVmware::where('vmware_id', $vm_id)->first();
if (!$vm) {
$vm = ModuleVmware::where('id', $vm_id)->first();
}
if (!$vm) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin máy ảo'
]);
}
if ($vm->customer_id != user()->id) {
return response()->json([
'error' => true,
'message' => 'Không có quyền truy cập máy ảo này'
]);
}
if ($vm->status == 4) {
return response()->json(['error' => true, 'message' => 'Dịch vụ đã hết hạn']);
}
if ($vm->status == 3) {
return response()->json(['error' => true, 'message' => 'Máy ảo đang khởi tạo']);
}
$vcenter = null;
if ($vm->ipAddress && $vm->ipAddress->host && $vm->ipAddress->host->datacenter && $vm->ipAddress->host->datacenter->vCenter) {
$vcenter = $vm->ipAddress->host->datacenter->vCenter;
}
if (!$vcenter) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin vCenter'
]);
}
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
]);
}
$result = $serviceVCenter->ShutdownGuestVirtualMachine($vm_id);
if ($result === "Login_Again") {
if ($serviceVCenter->loginServer($vcenter)) {
$result = $serviceVCenter->ShutdownGuestVirtualMachine($vm_id);
} else {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập lại vào vCenter'
]);
}
}
// Check if result is still a string (Login_Again or other error)
if (is_string($result)) {
return response()->json(['error' => true, 'message' => "Failed to stop virtual machine: $result"]);
}
if ($result['error']) {
return response()->json(['error' => true, 'message' => $result['data']]);
}
$vm->update(['status' => 0]);
return response()->json([
'error' => false,
'message' => 'Tắt máy ảo thành công'
]);
})->name('api.user.StopVirtualMachine');
Route::get('get-ip-address', function (Request $request, ServiceVCenter $serviceVCenter) {
try {
$validator = Validator::make($request->all(), [
'vm_id' => 'required|string|max:255',
]);
if ($validator->fails()) {
return response()->json([
'error' => true,
'message' => 'Dữ liệu không hợp lệ',
'errors' => $validator->errors()
], 422);
}
$vmId = $request->input('vm_id');
$vm = ModuleVmware::where('vmware_id', $vmId)
->orWhere('id', $vmId)
->first();
if (!$vm) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin máy ảo'
], 404);
}
if ($vm->status == 4) {
return response()->json([
'error' => true,
'message' => 'Dịch vụ đã hết hạn'
], 400);
}
if ($vm->status == 3) {
return response()->json([
'error' => true,
'message' => 'Máy ảo đang khởi tạo'
], 400);
}
$vcenter = $vm->ipAddress->host->datacenter->vCenter ?? null;
if (!$vcenter) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin vCenter'
], 500);
}
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
], 500);
}
// Gọi 2 endpoint
$identity = Http::withoutVerifying()
->withHeaders(['vmware-api-session-id' => $serviceVCenter->token])
->get("https://{$serviceVCenter->apiUri}/rest/vcenter/vm/{$vm->vmware_id}/guest/identity")
->json();
$networking = Http::withoutVerifying()
->withHeaders(['vmware-api-session-id' => $serviceVCenter->token])
->get("https://{$serviceVCenter->apiUri}/rest/vcenter/vm/{$vm->vmware_id}/guest/networking")
->json();
// Parse IP
$ipAddresses = [];
// (1) Từ networking
if (isset($networking['value']['interfaces'])) {
foreach ($networking['value']['interfaces'] as $interface) {
foreach ($interface['ip_addresses'] ?? [] as $ip) {
if (isset($ip['ip_address']) && filter_var($ip['ip_address'], FILTER_VALIDATE_IP)) {
$ipAddresses[] = [
'ip' => $ip['ip_address'],
'type' => $ip['type'] ?? 'unknown',
'state' => $ip['state'] ?? 'unknown',
];
}
}
}
}
// (2) Nếu networking rỗng, fallback từ identity
if (empty($ipAddresses) && isset($identity['value']['ip_address'])) {
$ip = $identity['value']['ip_address'];
if (filter_var($ip, FILTER_VALIDATE_IP)) {
$ipAddresses[] = [
'ip' => $ip,
'type' => strpos($ip, ':') !== false ? 'IPV6' : 'IPV4',
'state' => 'unknown',
];
}
}
// Update trạng thái
if (!empty($ipAddresses)) {
$vm->update(['status' => 1]);
}
return response()->json([
'error' => false,
'message' => 'Lấy IP address thành công',
'data' => [
'vm_id' => $vm->vmware_id,
'hostname' => $vm->hostname,
'status' => $vm->status,
'ip_addresses' => $ipAddresses,
'guest_info' => [
'family' => $identity['value']['family'] ?? null,
'full_name' => $identity['value']['full_name']['default_message'] ?? null,
'host_name' => $identity['value']['host_name'] ?? null,
]
]
]);
} catch (\Exception $e) {
Log::error('❌ Lỗi khi lấy IP address của VM', [
'vm_id' => $request->input('vm_id'),
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return response()->json([
'error' => true,
'message' => 'Lỗi hệ thống: ' . $e->getMessage()
], 500);
}
})->name('api.user.GetIPAddress');
Route::get('get-vm-info', function (Request $request, ServiceVCenter $serviceVCenter) {
try {
$validator = Validator::make($request->all(), [
'vm_id' => 'required|string|max:255',
]);
if ($validator->fails()) {
return response()->json([
'error' => true,
'message' => 'Dữ liệu không hợp lệ',
'errors' => $validator->errors()
], 422);
}
$vmId = $request->input('vm_id');
$vcenter = vCenter::first();
if (!$vcenter) {
return response()->json([
'error' => true,
'message' => 'Không tìm thấy thông tin vCenter'
], 500);
}
// Sử dụng token có sẵn nếu có
$serviceVCenter->apiUri = $vcenter->host;
$serviceVCenter->token = $vcenter->token;
// Gọi API với timeout 5s
$vmInfo = Http::withoutVerifying()
->timeout(5)
->withHeaders(['vmware-api-session-id' => $serviceVCenter->token])
->get("https://{$serviceVCenter->apiUri}/rest/vcenter/vm/{$vmId}")
->json();
// Nếu token hết hạn, login lại 1 lần duy nhất
if (isset($vmInfo['type']) && str_contains($vmInfo['value']['messages'][0]['default_message'] ?? '', 'session')) {
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => 'Không thể đăng nhập vào vCenter'
], 500);
}
// Thử lại với token mới
$vmInfo = Http::withoutVerifying()
->timeout(5)
->withHeaders(['vmware-api-session-id' => $serviceVCenter->token])
->get("https://{$serviceVCenter->apiUri}/rest/vcenter/vm/{$vmId}")
->json();
}
if (isset($vmInfo['type'])) {
return response()->json([
'error' => true,
'message' => 'Không thể lấy thông tin VM từ vCenter'
], 500);
}
return response()->json([
'error' => false,
'message' => 'Lấy thông tin VM thành công',
'data' => [
'vm_id' => $vmId,
'name' => $vmInfo['value']['name'] ?? 'Unknown',
'guest_os' => $vmInfo['value']['guest_OS'] ?? 'UNKNOWN',
'power_state' => $vmInfo['value']['power_state'] ?? 'UNKNOWN',
'cpu' => [
'count' => $vmInfo['value']['cpu']['count'] ?? 0,
'cores_per_socket' => $vmInfo['value']['cpu']['cores_per_socket'] ?? 0,
'hot_add_enabled' => $vmInfo['value']['cpu']['hot_add_enabled'] ?? false,
],
'memory' => [
'size_MiB' => $vmInfo['value']['memory']['size_MiB'] ?? 0,
'hot_add_enabled' => $vmInfo['value']['memory']['hot_add_enabled'] ?? false,
],
'disks' => array_map(function ($disk) {
return [
'key' => $disk['key'] ?? '',
'label' => $disk['value']['label'] ?? '',
'capacity' => $disk['value']['capacity'] ?? 0,
'type' => $disk['value']['type'] ?? '',
];
}, $vmInfo['value']['disks'] ?? []),
'nics' => array_map(function ($nic) {
return [
'key' => $nic['key'] ?? '',
'label' => $nic['value']['label'] ?? '',
'mac_address' => $nic['value']['mac_address'] ?? '',
'network_name' => $nic['value']['backing']['network_name'] ?? '',
'state' => $nic['value']['state'] ?? '',
];
}, $vmInfo['value']['nics'] ?? []),
'identity' => [
'instance_uuid' => $vmInfo['value']['identity']['instance_uuid'] ?? '',
'bios_uuid' => $vmInfo['value']['identity']['bios_uuid'] ?? '',
],
'hardware' => [
'version' => $vmInfo['value']['hardware']['version'] ?? '',
'upgrade_policy' => $vmInfo['value']['hardware']['upgrade_policy'] ?? '',
],
'boot' => [
'type' => $vmInfo['value']['boot']['type'] ?? '',
'efi_legacy_boot' => $vmInfo['value']['boot']['efi_legacy_boot'] ?? false,
]
],
'raw_data' => $vmInfo['value'] ?? null
]);
} catch (\Exception $e) {
Log::error('❌ Lỗi khi lấy thông tin VM', [
'vm_id' => $request->input('vm_id'),
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return response()->json([
'error' => true,
'message' => 'Lỗi hệ thống: ' . $e->getMessage()
], 500);
}
})->name('api.user.GetVMInfo');
Route::get('get-vm-info/{vm_id}/{params?}', function (Request $request, ServiceVCenter $serviceVCenter, $vm_id, $params = null) {
try {
$vcenter = vCenter::first();
if (!$vcenter) {
return response()->json([
'error' => true,
'message' => __('vCenter configuration not found')
], 500);
}
// Login to vCenter first
if (!$serviceVCenter->loginServer($vcenter)) {
return response()->json([
'error' => true,
'message' => __('Cannot login to vCenter')
], 500);
}
$vmInfo = $serviceVCenter->GetDetailVirtualMachine($vm_id);
if ($vmInfo['error']) {
return response()->json([
'error' => true,
'message' => __('Cannot get VM information from vCenter')
], 500);
}
$vmData = $vmInfo['data'];
// Parse các tham số được yêu cầu
$requestedParams = [];
if ($params) {
// Tách các param bằng dấu phẩy hoặc dấu +
$requestedParams = preg_split('/[,+]/', $params);
}
// Mapping dữ liệu đầy đủ
$allData = [
'vm_id' => $vm_id,
'name' => $vmData['name'] ?? 'Unknown',
'guest_os' => $vmData['guest_OS'] ?? 'UNKNOWN',
'power_state' => $vmData['power_state'] ?? 'UNKNOWN',
'cpu_count' => $vmData['cpu']['count'] ?? 0,
'cpu_cores_per_socket' => $vmData['cpu']['cores_per_socket'] ?? 0,
'cpu_hot_add' => $vmData['cpu']['hot_add_enabled'] ?? false,
'memory_size' => $vmData['memory']['size_MiB'] ?? 0,
'memory_hot_add' => $vmData['memory']['hot_add_enabled'] ?? false,
'instance_uuid' => $vmData['identity']['instance_uuid'] ?? '',
'bios_uuid' => $vmData['identity']['bios_uuid'] ?? '',
'hardware_version' => $vmData['hardware']['version'] ?? '',
'boot_type' => $vmData['boot']['type'] ?? '',
'efi_legacy_boot' => $vmData['boot']['efi_legacy_boot'] ?? false,
];
// Thêm thông tin disk
if (isset($vmData['disks']) && !empty($vmData['disks'])) {
$firstDisk = $vmData['disks'][0] ?? null;
if ($firstDisk) {
$allData['disk_capacity'] = $firstDisk['value']['capacity'] ?? 0;
$allData['disk_label'] = $firstDisk['value']['label'] ?? '';
$allData['disk_type'] = $firstDisk['value']['type'] ?? '';
}
}
// Thêm thông tin network
if (isset($vmData['nics']) && !empty($vmData['nics'])) {
$firstNic = $vmData['nics'][0] ?? null;
if ($firstNic) {
$allData['mac_address'] = $firstNic['value']['mac_address'] ?? '';
$allData['network_name'] = $firstNic['value']['backing']['network_name'] ?? '';
$allData['network_state'] = $firstNic['value']['state'] ?? '';
}
}
// Nếu không có params cụ thể, trả về tất cả
if (empty($requestedParams)) {
return response()->json([
'error' => false,
'message' => __('Successfully retrieved all VM information'),
'data' => $allData
]);
}
// Lọc chỉ những thông tin được yêu cầu
$filteredData = [];
foreach ($requestedParams as $param) {
$param = trim($param);
if (array_key_exists($param, $allData)) {
$filteredData[$param] = $allData[$param];
} else {
$filteredData[$param] = null; // Hoặc có thể bỏ qua
}
}
return response()->json([
'error' => false,
'message' => __('Successfully retrieved VM information'),
'data' => $filteredData
]);
} catch (\Exception $e) {
Log::error('❌ Lỗi khi lấy thông tin VM với params', [
'vm_id' => $vm_id,
'params' => $params,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return response()->json([
'error' => true,
'message' => __('System error: :error', ['error' => $e->getMessage()])
], 500);
}
})->name('api.user.GetVMInfoWithParams');
});
});
Route::any('{any}', function () {
return response()->json([
'error' => true,
'message' => 'API Route not found'
], 404);
})->where('any', '.*');